Необходимо оптимизировать маркетинговые затраты Яндекс.Афиши. В распоряжении есть данные с июня 2017 по конец мая 2018 года:
Цель проекта - изучить, как люди пользуются продуктом, когда они начинают покупать, сколько денег приносит каждый клиент, когда клиент окупается.
Для этого необходимо построить отчёты и посчитать метрики:
# импортируем необходимые библиотеки
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams.update({'font.size': 16})
import matplotlib
matplotlib.style.use('seaborn-darkgrid')
from pylab import rcParams
rcParams['figure.figsize'] = 18, 9
pd.set_option('display.max_columns', None)
pd.options.display.float_format = '{:,.2f}'.format
# %%HTML
# <style type="text/css">
# table.dataframe td, table.dataframe th {
# border: 1px black solid !important;
# color: black !important;
# }
# прочитаем DataFrame
try:
visits = pd.read_csv('visits_log.csv') # локальный путь
except:
visits = pd.read_csv('/datasets/visits_log.csv') # путь на сервере
# выведем на экран 10 случайных строк таблицы
visits.sample(10)
# посмотрим сводную информацию таблицы
visits.info()
В таблице 359400 строк, 5 столбцов, тип данных у трёх столбцов строковый, у двух - целочисленный. В названии столбцов есть строчные буквы и пробелы. В столбцах Start Ts и End Ts значения даты и времени начала и окончания сессии указаны не в формате datetime.
# посмотрим количество уникальных значений по столбцам таблицы
for column in visits.columns:
print(column)
print()
print(visits[column].value_counts())
print()
Пользователи посещали сайт с устройств двух категорий, пришли из 9 вариантов рекламных источников. За анализируемый период сайт посещало 228169 уникальных пользователей, количество посещений одним пользователем - от 1 до 893.
# найдем долю посещений на различных категориях устройств
round(visits['Device'].value_counts(normalize = True) * 100, 1)
73,1% посещений произведено со стационарных устройств, 26,9% - с мобильных.
# определим период информации в таблице
(visits['Start Ts'].min(), visits['Start Ts'].max())
В таблице содержится информация за период с 01.06.2017 по 31.05.2018.
# определим долю строк, где время начала сессии совпадает со временем ее окончания
round(len(visits.loc[visits['End Ts'] == visits['Start Ts']]) / len(visits) * 100, 1)
В 10% строк таблицы время начала сессии совпадает со временем ее окончания. Так как время в таблице указано с округлением до минут, вероятнее всего пользовательская сессия в этих случаях продлилась не более минуты.
# найдем строки, где время начала сессии позже времени ее окончания
visits.loc[visits['End Ts'] < visits['Start Ts']]
Имеется две строки, в которых время начала сессии позже времени ее окончания. Вероятнее всего это сбой при выгрузке данных.
# найдем долю посещений из различных рекламных источников
round(visits['Source Id'].value_counts(normalize = True) * 100, 1)
Самый популярный - четвертый рекламный источник, из которого пришло 28,3% пользователей.
# определим количество пропущенных значений в таблице
visits.isnull().sum()
Пропущенные значения отсутствуют.
# посчитаем количество дубликатов
visits.duplicated().sum()
Дубликаты отсутствуют.
# прочитаем DataFrame
try:
orders = pd.read_csv('orders_log.csv') # локальный путь
except:
orders = pd.read_csv('/datasets/orders_log.csv') # путь на сервере
# выведем на экран 10 случайных строк таблицы
orders.sample(10)
# посмотрим сводную информацию таблицы
orders.info()
В таблице 50415 строк, 3 столбца, тип данных у одного столбца строковый, у одного - целочисленный, у одного - вещественный. В названии столбцов есть строчные буквы и пробелы. В столбце Buy Ts значения даты и времени заказа указаны не в формате datetime.
# проведем базовую проверку столбца с выручкой
orders['Revenue'].describe()
В среднем выручка от одного заказа составляет около 5 рублей, более 75% заказов приносят выручку ниже средней, максимальная выручка от одного заказа - 2633,28 рубля.
# посмотрим на строки таблицы с выручкой более 1000 рублей
orders.query('Revenue > 1000')
Было совершено 7 крупных покупок стоимостью более 1000 рублей каждая, эти покупки были совершены двумя покупателями. 3 таких покупки были совершены в декабре 2017 года, 2 - в феврале 2018 года. Вероятнее всего это корпоративные клиенты, покупавшие билеты для своих работников, либо перекупщики билетов, решившие заработать на наиболее популярных мероприятиях.
# посмотрим количество уникальных значений по столбцам таблицы
for column in orders.columns:
print(column)
print()
print(orders[column].value_counts())
print()
За анализируемый период заказы осуществило 36523 уникальных пользователя, количество заказов одного пользователя - от 1 до 239.
# определим период информации в таблице
(orders['Buy Ts'].min(), orders['Buy Ts'].max())
В таблице содержится информация за период с 01.06.2017 по 01.06.2018. Рассмотрим строки с информацией вне анализируемого периода.
# найдем строки таблицы с заказами с информацией вне анализируемого периода
orders[orders['Buy Ts'] >= '2018-06-01 00:00:00']
Имеется одна строка с оплатой заказа вне анализируемого периода. Найдем все посещения сайта данным пользователем.
# найдем строки таблицы с посещениями с информацией вне анализируемого периода
visits.query('Uid == "83872787173869366"')
Сессия началась 31.05.2018 в 23:59:00, вся ее продолжительность пришлась на дату вне анализируемого периода.
# посчитаем количество строк таблицы с нулевой выручкой
len(orders.query('Revenue == 0'))
Имеется 51 значение с нулевой выручкой от заказа (вероятнее всего реализованы либо акционные, либо льготные билеты).
# определим количество пропущенных значений в таблице
orders.isnull().sum()
Пропущенные значения отсутствуют.
# посчитаем количество дубликатов
orders.duplicated().sum()
Дубликаты отсутствуют.
# прочитаем DataFrame
try:
costs = pd.read_csv('costs.csv') # локальный путь
except:
costs = pd.read_csv('/datasets/costs.csv') # путь на сервере
# выведем на экран 10 случайных строк таблицы
costs.sample(10)
# посмотрим сводную информацию таблицы
costs.info()
В таблице 2542 строки, 3 столбца, тип данных у одного столбца строковый, у одного - целочисленный, у одного - вещественный. В столбце dt значения даты осуществления рекламных затрат указаны не в формате datetime.
# проведем базовую проверку столбца с затратами
costs['costs'].describe()
В среднем ежедневные рекламные затраты на один источник составляют около 129 рублей, максимальные ежедневные затраты на один источник - 1788,28 рублей, минимальные - 0,54 рубля.
# посмотрим количество уникальных значений по столбцам таблицы
for column in costs.columns:
print(column)
print()
print(costs[column].value_counts())
print()
Всего затраты осуществлялись на 7 рекламных источников. На все рекламные источники траты осуществлялись ежедневно за исключением 31.03.2018, когда затраты были произведены только на пятый рекламный источник. Не осуществлялись затраты на шестой и седьмой рекламные источники, из которых пришли пользователи, осуществившие соответственно 6 и 36 посещений сайта.
# определим период информации в таблице
(costs['dt'].min(), costs['dt'].max())
В таблице содержится информация за период с 01.06.2017 по 31.05.2018.
# определим количество пропущенных значений в таблице
costs.isnull().sum()
Пропущенные значения отсутствуют.
# посчитаем количество дубликатов
costs.duplicated().sum()
Дубликаты отсутствуют.
При изучении таблиц с данными установлено следующее:
visits (лог сервера с информацией о посещениях сайта): Start Ts и End Ts значения даты и времени начала и окончания сессии указаны не в формате datetime; orders (информация о заказах):Buy Ts значения даты и времени заказа указаны не в формате datetime. costs (информация о затратах на маркетинг):dt значения даты осуществления рекламных затрат указаны не в формате datetime. Проанализировав вышеизложенное, необходимо выполнить следующее:
visits и orders привести к нижнему регистру, из названий убрать пробелы; visits, даты и времени заказа в таблице orders, даты осуществления рекламных затрат в таблице costs привести к формату datetime; visits; visits и orders удалить строки с информацией вне анализируемого периода.# поменяем названия столбцов
visits.columns = ['device',
'session_end_ts',
'source_id',
'session_start_ts',
'uid']
visits.head()
# поменяем порядок столбцов
visits = visits[['uid',
'device',
'source_id',
'session_start_ts',
'session_end_ts']]
visits.head()
# поменяем местами строки, где время начала сессии позже времени ее окончания
visits.loc[4181, ['session_start_ts', 'session_end_ts']]\
= visits.loc[4181, ['session_end_ts', 'session_start_ts']].values
visits.loc[177972, ['session_start_ts', 'session_end_ts']]\
= visits.loc[177972, ['session_end_ts', 'session_start_ts']].values
(visits.loc[4181, ['session_start_ts', 'session_end_ts']],
visits.loc[177972, ['session_start_ts', 'session_end_ts']])
# удалим строку вне анализируемого периода
visits = visits.drop(index = 299620)\
.reset_index(drop = True)
visits.info()
# приведем значения даты и времени начала и окончания сессии к формату "datetime"
visits['session_start_ts'] = pd.to_datetime(visits['session_start_ts'],
format = '%Y-%m-%d %H:%M:%S')
visits['session_end_ts'] = pd.to_datetime(visits['session_end_ts'],
format = '%Y-%m-%d %H:%M:%S')
visits.info()
# поменяем названия столбцов
orders.columns = ['order_ts',
'revenue',
'uid']
orders.head()
# поменяем порядок столбцов
orders = orders[['uid',
'revenue',
'order_ts']]
orders.head()
# удалим строку вне анализируемого периода
orders = orders.drop(index = 50414)\
.reset_index(drop = True)
orders.info()
# приведем значения даты и времени заказа к формату "datetime"
orders['order_ts'] = pd.to_datetime(orders['order_ts'],
format = '%Y-%m-%d %H:%M:%S')
orders.info()
# поменяем названия столбцов
costs.columns = ['source_id',
'date',
'costs']
costs.head()
# поменяем порядок столбцов
costs = costs[['source_id',
'costs',
'date']]
costs.head()
# приведем значения даты осуществления затрат к формату "datetime"
costs['date'] = pd.to_datetime(costs['date'],
format = '%Y-%m-%d')
costs.info()
В целях подготовки данных провели следующую работу:
visits и orders привели к нижнему регистру, из названий убрали пробелы; visits, даты и времени заказа в таблице orders, даты осуществления затрат на маркетинг в таблице costs привели к формату datetime; visits; visits и orders удалили строки с информацией вне анализируемого периода.# добавим в таблицу столбцы с годом, месяцем, неделей, днем недели и днем сессии
visits['session_year'] = visits['session_start_ts'].dt.year
visits['session_month'] = visits['session_start_ts'].astype('datetime64[M]')
visits['session_week'] = visits['session_start_ts'].astype('datetime64[W]')
visits['session_day_of_week'] = visits['session_start_ts'].dt.weekday
visits['session_date'] = visits['session_start_ts'].dt.date
visits.head()
# посмотрим на динамику количества уникальных пользователей в день
dau = visits.groupby('session_date')\
.agg({'uid': 'nunique'})\
.reset_index()
fig, ax = plt.subplots()
plt.title('Динамика количества уникальных пользователей в день')
ax = sns.lineplot(x = 'session_date',
y = 'uid',
data = dau)
plt.xlabel('Месяц')
plt.ylabel('Количество пользователей')
plt.show()
Динамика количества уникальных пользователей в день очень неравномерна, на графике имеются "зубцы", которые, вероятнее всего, свидетельствуют о разном распределении пользователей по дням недели.
# посмотрим на количество уникальных пользователей по дням недели
nunique_day_of_week = visits.groupby('session_day_of_week')\
.agg({'uid': 'nunique'})\
.reset_index()
day_of_week = ['Понедельник',
'Вторник',
'Среда',
'Четверг',
'Пятница',
'Суббота',
'Воскресенье']
fig, ax = plt.subplots()
plt.title('Количество уникальных пользователей по дням недели')
ax = sns.barplot(x = 'session_day_of_week',
y = 'uid',
data = nunique_day_of_week)
plt.xlabel('День недели')
plt.ylabel('Количество пользователей')
ax.set_xticklabels(labels = day_of_week)
plt.show()
Как и предполагалось, в выходные дни количество уникальных пользователей на сайте падает, наибольшее количество таких пользователей по четвергам.
# посмотрим на динамику количества уникальных пользователей в неделю
wau = visits.groupby('session_week')\
.agg({'uid': 'nunique'})\
.reset_index()
fig, ax = plt.subplots()
plt.title('Динамика количества уникальных пользователей в неделю')
ax = sns.lineplot(x = 'session_week',
y = 'uid',
data = wau)
plt.xlabel('Месяц')
plt.ylabel('Количество пользователей')
plt.show()
Имеется значительный недельный "всплеск" привлечения уникальных пользователей в конце декабря 2017 года, вероятнее всего связанный с новогодними праздниками. Кроме того есть небольшие "всплески" в начале октября 2017 года и середине марта 2018 года. В свою очередь "спад" отмечался в начале августа 2017 года и конце марта 2018 года.
# посмотрим на динамику количества уникальных пользователей в месяц
mau = visits.groupby('session_month')\
.agg({'uid': 'nunique'})\
.reset_index()
fig, ax = plt.subplots()
plt.title('Динамика количества уникальных пользователей в месяц')
ax = sns.lineplot(x = 'session_month',
y = 'uid',
data = mau)
plt.xlabel('Месяц')
plt.ylabel('Количество пользователей')
plt.show()
Наибольшее количество уникальных пользователей было привлечено на сайт в ноябре 2017 года, после которого их количество неуклонно снижается, наименьшее - в августе 2017 года.
# посчитаем средние метрики пользовательской активности
users_unique_count = visits['uid'].agg('nunique')
dau_total = visits.groupby('session_date').agg({'uid': 'nunique'}).mean()
wau_total = visits.groupby(['session_year', 'session_week']).agg({'uid': 'nunique'}).mean()
mau_total = visits.groupby(['session_year', 'session_month']).agg({'uid': 'nunique'}).mean()
sticky_factor_wau = dau_total / wau_total * 100
sticky_factor_mau = dau_total / mau_total * 100
d = {'n_users': users_unique_count,
'dau': int(dau_total),
'wau': int(wau_total),
'mau': int(mau_total),
'sticky_factor_wau_pct': float(sticky_factor_wau),
'sticky_factor_mau_pct': float(sticky_factor_mau)}
visits_metrics_all = pd.DataFrame(data = d,
index = ['all'])
visits_metrics_all
Общее количество уникальных пользователей - 228168. Среднее количество уникальных пользователей в день - 907, в неделю - 5621, в месяц - 23228. Вовлечённость недельной аудитории - 16,15%, месячной - 3,91%.
# напишем функцию для расчета метрик пользовательской активности по различным группам
def user_activity(df, column):
columns = [column, 'n_users', 'dau', 'wau', 'mau', 'sticky_factor_wau_pct', 'sticky_factor_mau_pct']
visits_metrics = pd.DataFrame([], columns = columns)
visits_metrics[column] = df[column].sort_values().unique()
for parameter in visits_metrics[column]:
visits_metrics.loc[visits_metrics[column] == parameter, 'n_users'] = \
df.loc[df[column] == parameter]['uid'].agg('nunique')
visits_metrics.loc[visits_metrics[column] == parameter, 'dau'] = \
int(df.loc[df[column] == parameter].groupby('session_date').agg({'uid': 'nunique'}).mean())
visits_metrics.loc[visits_metrics[column] == parameter, 'wau'] = \
int(df.loc[df[column] == parameter].groupby(['session_year', 'session_week']).agg({'uid': 'nunique'}).mean())
visits_metrics.loc[visits_metrics[column] == parameter, 'mau'] = \
int(df.loc[df[column] == parameter].groupby(['session_year', 'session_month']).agg({'uid': 'nunique'}).mean())
visits_metrics['sticky_factor_wau_pct'] = visits_metrics['dau'] / visits_metrics['wau'] * 100
visits_metrics['sticky_factor_mau_pct'] = visits_metrics['dau'] / visits_metrics['mau'] * 100
return visits_metrics
# применим функцию для расчета метрик пользовательской активности по категориям устройств
visits_metrics_device = user_activity(visits,
'device')
visits_metrics_device
# посмотрим на распределение количества уникальных пользователей по категориям устройств
fig, ax = plt.subplots(figsize = (9, 9))
plt.title('Распределение количества уникальных пользователей по категориям устройств')
ax = sns.barplot(x = 'device',
y = 'n_users',
data = visits_metrics_device)
plt.xlabel('Категория устройства')
plt.ylabel('Количество пользователей')
plt.show()
Общее количество уникальных пользователей, использующих стационарные устройства, - 164522, мобильные - 71345. Сумма рассчитанных показателей больше, чем общее количество уникальных пользователей, так как есть пользователи, которые для посещения сайта используют как стационарные, так и мобильные устройства. Среднее количество уникальных пользователей в день со стационарных устройств - 659, с мобильных - 252, в неделю - соответственно 4061 и 1607, в месяц - соответственно 16724 и 6825. Показатели вовлечённости пользователей практически равны на разных устройствах, в то же время на стационарных устройствах они незначительно выше, чем на мобильных.
# определим количество пользователей, которые для посещения сайта используют как стационарные, так и мобильные устройства
a = visits.query('device == "desktop"')['uid']\
.value_counts().index.to_list()
visits.query('device == "touch" and uid == @a')['uid']\
.agg('nunique')
7699 пользователей для посещения сайта используют как стационарные, так и мобильные устройства.
# проверим правильность расчетов
visits_metrics_device['n_users'].sum()\
- visits.query('device == "touch" and uid == @a')['uid'].agg('nunique')\
- visits_metrics_all['n_users'].sum()
# применим функцию для расчета метрик пользовательской активности по рекламным источникам
visits_metrics_source = user_activity(visits,
'source_id')
visits_metrics_source
# посмотрим на распределение количества уникальных пользователей по рекламным источникам
fig, ax = plt.subplots()
plt.title('Распределение количества уникальных пользователей по рекламным источникам')
ax = sns.barplot(x = 'source_id',
y = 'n_users',
data = visits_metrics_source)
plt.xlabel('Рекламный источник')
plt.ylabel('Количество пользователей')
plt.show()
Наибольшее общее количество уникальных пользователей привлечено на сайт при помощи четвертого рекламного источника - 83524, при помощи третьего - 74756. Сумма рассчитанных показателей больше, чем общее количество уникальных пользователей, так как есть пользователи, которые были привлечены с использованием различных источников. Наибольшее среднее количество уникальных пользователей было привлечено на сайт также при помощи четвертого рекламного источника (275 в день, 1797 в неделю и 7765 в месяц), при помощи третьего источника в среднем привлечено 232 пользователя в день, 1536 в неделю и 6758 в месяц. При помощи шестого и седьмого рекламных источников пользователи практически не привлекались. Показатели вовлечённости аудитории выше у первого и второго рекламных источников.
# посмотрим на динамику количества сессий в день
sessions_per_user = visits.groupby('session_date')\
.agg({'uid': ['count','nunique']})\
.reset_index()
sessions_per_user.columns = ['session_date',
'n_sessions',
'n_users']
sessions_per_user['sessions_per_user'] = sessions_per_user['n_sessions'] / sessions_per_user['n_users']
fig, ax = plt.subplots()
plt.title('Динамика количества сессий в день')
ax = sns.lineplot(x = 'session_date',
y = 'n_sessions',
data = sessions_per_user)
plt.xlabel('Месяц')
plt.ylabel('Количество сессий')
plt.show()
Имеется заметный "всплеск" в декабре, вероятнее всего связанный с новогодними праздниками. Также был небольшой "всплеск" в середине июля, середине февраля, ближе к концу марта, в конце мая. В то же время в конце марта - начале апреля имеется заметный "спад". Вероятнее всего, это связано с техническими неполадками на сайте.
# рассчитаем статистические показатели количества сессий в день
min_sessions_per_day = sessions_per_user['n_sessions'].agg('min')
max_sessions_per_day = sessions_per_user['n_sessions'].agg('max')
mean_sessions_per_day = sessions_per_user['n_sessions'].agg('mean')
median_sessions_per_day = int(sessions_per_user['n_sessions'].agg('median'))
d = {'min_sessions_per_day': min_sessions_per_day,
'max_sessions_per_day': max_sessions_per_day,
'mean_sessions_per_day': mean_sessions_per_day,
'median_sessions_per_day': median_sessions_per_day}
sessions_metrics_all = pd.DataFrame(data = d,
index = ['all'])
sessions_metrics_all
Минимальное количество сессий в день - 1, максимальное - 4042, среднее - 987, медианное - 1003. Поскольку среднее арифметическое незначительно отличается от медианы, в качестве основного показателя среднего количества сессий в день применим среднее арифметическое.
# оставим в таблице основной показатель меры центральной тенденции
sessions_metrics_all = sessions_metrics_all[['mean_sessions_per_day']].astype('int')\
.rename(columns = {'mean_sessions_per_day':'avg_sessions_per_day'})
sessions_metrics_all
# определим день с одной сессией
sessions_per_user.query('n_sessions == 1')
Всего одна сессия была 31.03.2018. Как было ранее установлено, именно в этот день затраты были произведены только на пятый рекламный источник. Вероятнее всего, как уже было отмечено, на сайте в этот день были технические неполадки.
# посмотрим на динамику количества сессий в день на одного пользователя
fig, ax = plt.subplots()
plt.title('Динамика количества сессий в день на одного пользователя')
ax = sns.lineplot(x = 'session_date',
y = 'sessions_per_user',
data = sessions_per_user)
plt.xlabel('Месяц')
plt.ylabel('Количество сессий')
plt.show()
Динамика ежедневного количества сессий, приходящихся на одного пользователя, близка к динамике количества ежедневных сессий с аналогичными "всплесками" и "спадами".
# рассчитаем статистические показатели количества сессий в день на одного пользователя
min_sessions_per_user_day = sessions_per_user['sessions_per_user'].agg('min')
max_sessions_per_user_day = sessions_per_user['sessions_per_user'].agg('max')
mean_sessions_per_user_day = sessions_per_user['sessions_per_user'].agg('mean')
median_sessions_per_user_day = sessions_per_user['sessions_per_user'].agg('median')
d = {'min_sessions_per_user_day': min_sessions_per_user_day,
'max_sessions_per_user_day': max_sessions_per_user_day,
'mean_sessions_per_user_day': mean_sessions_per_user_day,
'median_sessions_per_user_day': median_sessions_per_user_day}
sessions_metrics_user_all = pd.DataFrame(data = d,
index = ['all'])
sessions_metrics_user_all
Минимальное ежедневное количество сессий, приходящихся на одного пользователя, - 1, максимальное - 1,22, среднее и медианное - 1,08. Поскольку среднее арифметическое не отличается от медианы, в качестве основного показателя среднего количества сессий в день на одного пользователя применим среднее арифметическое.
# оставим в таблице основной показатель меры центральной тенденции
sessions_metrics_all['avg_sessions_per_user_day'] = sessions_metrics_user_all['mean_sessions_per_user_day']
sessions_metrics_all
# посмотрим на динамику количества сессий в день по категориям устройств
sessions_per_user_device = visits.groupby(['device', 'session_date'])\
.agg({'uid': ['count','nunique']})\
.reset_index()
sessions_per_user_device.columns = ['device',
'session_date',
'n_sessions',
'n_users']
sessions_per_user_device['sessions_per_user'] = sessions_per_user_device['n_sessions'] / sessions_per_user_device['n_users']
fig, ax = plt.subplots()
plt.title('Динамика количества сессий в день по категориям устройств')
ax = sns.lineplot(x = 'session_date',
y = 'n_sessions',
data = sessions_per_user_device,
hue = 'device')
plt.xlabel('Месяц')
plt.ylabel('Количество сессий')
plt.show()
Колебания количества сессий в день значительно выше при использовании стационарных устройств. Кроме того, ни в один из дней не было превышения случаев использования мобильных устройств для посещения сайта по сравнению со стационарными.
# рассчитаем статистические показатели количества сессий в день по категориям устройств
sessions_metrics_device = sessions_per_user_device.groupby('device')['n_sessions']\
.agg(['min', 'max', 'mean', 'median'])\
.rename(columns = {'min':'min_sessions_per_day',
'max':'max_sessions_per_day',
'mean':'mean_sessions_per_day',
'median':'median_sessions_per_day'})\
.reset_index()
sessions_metrics_device
Минимальное количество сессий в день при использовании стационарных устройств - 1, максимальное - 3152, среднее - 721, медианное - 711. При использовании мобильных устройств минимальное количество сессий в день - 47, максимальное - 890, среднее - 267, медианное - 278. Поскольку среднее арифметическое незначительно отличается от медианы, в качестве основного показателя среднего количества сессий в день применим среднее арифметическое.
# оставим в таблице основной показатель меры центральной тенденции
sessions_metrics_device = sessions_metrics_device[['device', 'mean_sessions_per_day']]\
.rename(columns = {'mean_sessions_per_day':'avg_sessions_per_day'})
sessions_metrics_device['avg_sessions_per_day'] = sessions_metrics_device['avg_sessions_per_day'].round().astype('int')
sessions_metrics_device
# посмотрим на динамику количества сессий в день на одного пользователя по категориям устройств
fig, ax = plt.subplots()
plt.title('Динамика количества сессий в день на одного пользователя по категориям устройств')
ax = sns.lineplot(x = 'session_date',
y = 'sessions_per_user',
data = sessions_per_user_device,
hue = 'device')
plt.xlabel('Месяц')
plt.ylabel('Количество сессий')
plt.show()
Динамика ежедневного количества сессий, приходящихся на одного пользователя, по категориям устройств близка к динамике количества ежедневных сессий. В то же время наблюдаются более значительные колебания этого показателя по сравнению с количеством ежедневных сессий у пользователей мобильных устройств, кроме того есть дни, когда количество сессий, приходящихся на одного пользователя, выше именно у владельцев мобильных устройств.
# рассчитаем статистические показатели количества сессий в день на одного пользователя по категориям устройств
sessions_metrics_user_device = sessions_per_user_device.groupby('device')['sessions_per_user']\
.agg(['min', 'max', 'mean', 'median'])\
.rename(columns = {'min':'min_sessions_per_user_day',
'max':'max_sessions_per_user_day',
'mean':'mean_sessions_per_user_day',
'median':'median_sessions_per_user_day'})\
.reset_index()
sessions_metrics_user_device
Минимальное количество сессий в день на одного пользователя при использовании стационарных устройств - 1, максимальное - 1,21, среднее и медианное - 1,09. При использовании мобильных устройств минимальное количество сессий в день на одного пользователя - 1, максимальное - 1,18, среднее и медианное чуть ниже, чем при использовании стационарных, - 1,05. Поскольку среднее арифметическое не отличается от медианы, в качестве основного показателя среднего количества сессий в день на одного пользователя применим среднее арифметическое.
# оставим в таблице основной показатель меры центральной тенденции
sessions_metrics_device['avg_sessions_per_user_day'] = sessions_metrics_user_device['mean_sessions_per_user_day']
sessions_metrics_device
# посмотрим на динамику количества сессий в день по рекламным источникам
sessions_per_user_source = visits.groupby(['source_id', 'session_date'])\
.agg({'uid': ['count','nunique']})\
.reset_index()
sessions_per_user_source.columns = ['source_id',
'session_date',
'n_sessions',
'n_users']
sessions_per_user_source['sessions_per_user'] = sessions_per_user_source['n_sessions'] / sessions_per_user_source['n_users']
fig, ax = plt.subplots()
ax.set(title = 'Динамика количества сессий в день по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Количество сессий')
for source in sessions_per_user_source['source_id'].unique():
ax.plot(sessions_per_user_source.query('source_id == @source')['session_date'],
sessions_per_user_source.query('source_id == @source')['n_sessions'],
label = source)
ax.grid = True
ax.legend(bbox_to_anchor = (0.81, 0.53))
plt.show()
Динамика количества сессий в день по рекламным источникам очень похожа, декабрьский "пик" при этом достигнут, в основном благодаря пользователям, пришедшим из третьего и четвертого рекламных источников.
# рассчитаем статистические показатели количества сессий в день по рекламным источникам
sessions_metrics_source = sessions_per_user_source.groupby('source_id')['n_sessions']\
.agg(['min', 'max', 'mean', 'median'])\
.rename(columns = {'min':'min_sessions_per_day',
'max':'max_sessions_per_day',
'mean':'mean_sessions_per_day',
'median':'median_sessions_per_day'})\
.reset_index()
sessions_metrics_source
У третьего рекламного источника самый высокий показатель максимального количества сессий в день - 965. Среднее количество сессий в день наибольшее у четвертого рекламного источника - 280, медианное у него же - 300. Поскольку на некоторых рекламных источниках среднее арифметическое существенно отличается от медианы, в качестве основного показателя среднего количества сессий в день применим медиану.
# оставим в таблице основной показатель меры центральной тенденции
sessions_metrics_source = sessions_metrics_source[['source_id', 'median_sessions_per_day']]\
.rename(columns = {'median_sessions_per_day':'avg_sessions_per_day'})
sessions_metrics_source
# посмотрим на динамику количества сессий в день на одного пользователя по рекламным источникам
fig, ax = plt.subplots()
ax.set(title = 'Динамика количества сессий в день на одного пользователя по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Количество сессий')
for source in sessions_per_user_source['source_id'].unique():
ax.plot(sessions_per_user_source.query('source_id == @source')['session_date'],
sessions_per_user_source.query('source_id == @source')['sessions_per_user'],
label = source)
ax.grid = True
ax.legend(bbox_to_anchor = (0.81, 0.53))
plt.show()
Динамика количества сессий в день на одного пользователя по рекламным источникам подвержена более значительным колебаниям, при этом у первого рекламного источника имеется самое большое количество "всплесков" этого показателя.
# рассчитаем статистические показатели количества сессий в день на одного пользователя по рекламным источникам
sessions_metrics_user_source = sessions_per_user_source.groupby('source_id')['sessions_per_user']\
.agg(['min', 'max', 'mean', 'median'])\
.rename(columns = {'min':'min_sessions_per_user_day',
'max':'max_sessions_per_user_day',
'mean':'mean_sessions_per_user_day',
'median':'median_sessions_per_user_day'})\
.reset_index()
sessions_metrics_user_source
Как уже отмечалось ранее, лучший рекламный источник по количеству сессий в день на одного пользователя - первый (максимальное - 1,47, среднее и медианное - 1,15). У третьего и четвертого рекламных источников, у которых наибольшие показатели абсолютного количества сессий в день, среднее количество сессий в день на одного пользователя близко к 1 - соответственно 1,01 и 1,02. Поскольку на некоторых рекламных источниках среднее арифметическое существенно отличается от медианы, в качестве основного показателя среднего количества сессий в день на одного пользователя применим медиану.
# оставим в таблице основной показатель меры центральной тенденции
sessions_metrics_source['avg_sessions_per_user_day'] = sessions_metrics_user_source['median_sessions_per_user_day']
sessions_metrics_source
# добавим в таблицу столбец с продолжительностью сессии в секундах
visits['session_duration_sec'] = (visits['session_end_ts'] - visits['session_start_ts']).dt.seconds
visits.head()
# посмотрим на распределение продолжительности сессий
fig, ax = plt.subplots()
ax.set(title = 'Распределение продолжительности сессий',
xlabel = 'Длительность сессии, секунд',
ylabel = 'Количество сессий')
ax.hist(visits['session_duration_sec'],
bins = 100)
plt.show()
Распределение продолжительности сессий очень неравномерно, наибольшее количество сессий с короткой продолжительностью, хотя имеются и весьма продолжительные сессии. Рассчитаем меры центральной тенденции и определим показатель, который лучше всего отразит метрику ASL.
# рассчитаем статистические показатели продолжительности сессии
session_duration_sec_mean = int(visits['session_duration_sec'].mean())
session_duration_sec_median = int(visits['session_duration_sec'].median())
session_duration_sec_mode = int(visits['session_duration_sec'].mode())
d = {'session_duration_sec_mean': session_duration_sec_mean,
'session_duration_sec_median': session_duration_sec_median,
'session_duration_sec_mode': session_duration_sec_mode}
asl_metrics_all = pd.DataFrame(data = d, index = ['all'])
asl_metrics_all
Средее арифметическое продолжительности сессии - 643 секунды, медиана - 300 секунд, мода - 60 секунд. Поскольку распределение продолжительности сессий не является нормальным и не близко к нормальному, среднее арифметическое и медиана не могут использоваться для оценки среднего показателя продолжительности сессии. Показателем ASL, в том числе в разрезе категорий устройств и рекламных источников, в данном случае будет являться мода.
# оставим в таблице основной показатель меры центральной тенденции
asl_metrics_all = asl_metrics_all[['session_duration_sec_mode']]\
.rename(columns = {'session_duration_sec_mode':'asl_sec'})
asl_metrics_all
# рассчитаем ASL по категориям устройств
asl_metrics_device = visits.groupby('device')['session_duration_sec']\
.apply(lambda x: x.mode().iloc[0])\
.reset_index()\
.rename(columns = {'session_duration_sec':'asl_sec'})
asl_metrics_device
Показатель средней продолжительности сессии ASL по категориям устройств соответствует общему показателю ASL.
# рассчитаем ASL по рекламным источникам
asl_metrics_source = visits.groupby('source_id')['session_duration_sec']\
.apply(lambda x: x.mode().iloc[0])\
.reset_index()\
.rename(columns = {'session_duration_sec':'asl_sec'})
asl_metrics_source
Показатель средней продолжительности сессии ASL по рекламным источникам соответствует общему показателю ASL, за исключением шестого и седьмого рекламных источников, при помощи которых привлечено небольшое количество пользователей.
# определим дату первого посещения сайта пользователями
first_session = visits.groupby('uid')\
.agg({'session_start_ts':'min'})\
.rename(columns = {'session_start_ts':'first_session'})
first_session.head()
# добавим в таблицу с визитами столбец с датой первого посещения сайта пользователями
visits = visits.join(first_session,
on = 'uid')
visits.head()
Исходя из предшествующего анализа, целесообразно проводить когортный анализ с периодом в 1 месяц.
# добавим в таблицу столбцы с месяцами посещения и первого посещения сайта пользователями
visits['activity_month'] = visits['session_date'].astype('datetime64[M]')
visits['first_session_month'] = visits['first_session'].astype('datetime64[M]')
visits.head()
# добавим в таблицу столбец с lifetime пользователей
visits['cohort_lifetime'] = visits['activity_month'] - visits['first_session_month']
visits['cohort_lifetime'] = visits['cohort_lifetime'] / np.timedelta64(1,'M')
visits['cohort_lifetime'] = visits['cohort_lifetime'].round()\
.astype('int')
visits.head()
# сформируем когорты пользователей по первому месяцу посещения сайта
cohorts = visits.groupby(['first_session_month','cohort_lifetime'])\
.agg({'uid':'nunique'})\
.reset_index()
cohorts.head()
# определим исходное количество пользователей в когортах
initial_users_count = cohorts[cohorts['cohort_lifetime'] == 0][['first_session_month','uid']]
initial_users_count = initial_users_count.rename(columns = {'uid':'cohort_users'})
initial_users_count
# добавим в таблицу столбец с исходным количеством пользователей в когортах
cohorts = cohorts.merge(initial_users_count,
on = 'first_session_month')
cohorts.head()
# посчитаем показатель Retention Rate по когортам и lifetime
cohorts['retention_rate'] = cohorts['uid'] / cohorts['cohort_users']
cohorts.head()
# построим сводную таблицу с показателем Retention Rate по когортам и lifetime
retention_rate = cohorts.pivot_table(index = 'first_session_month',
columns = 'cohort_lifetime',
values = 'retention_rate',
aggfunc = 'sum')
retention_rate.fillna('')
# создадим тепловую карту с показателем Retention Rate по когортам и lifetime
plt.figure(figsize = (15, 9))
plt.title('Retention Rate по когортам')
ax = sns.heatmap(retention_rate,
annot = True,
fmt = '.1%',
vmax = 0.09,
linewidths = 1,
cmap = 'coolwarm',
linecolor = 'gray',
yticklabels = retention_rate.index.date)
plt.xlabel('Lifetime')
plt.ylabel('Когорта')
plt.show()
Показатель возврата пользователя к продукту (Retention Rate) очень низок - ни в один из месяцев "жизни" когорты коэффициент удержания не был выше 10%, при этом со временем Retention Rate снижается. Retention Rate в первый месяц "жизни" убывает по когортам, начиная с января 2018 года. Так, если для когорты пользователей, пришедших в сентябре 2017 года, Retention Rate в первый месяц составлял 8,5%, то для пользователей, пришедших в декабре 2017 года, — всего 5,6%, и в дальнейшем уменьшается. Самые активные пользователи - впервые посетившие сайт в июне 2017 года, с течением времени Retention Rate у этой когорты не был менее 4%.
# посмотрим на динамику среднего Retention Rate по времени "жизни" когорты
retention_rate_mean = cohorts.groupby('cohort_lifetime')['retention_rate']\
.mean() * 100
fig, ax = plt.subplots()
plt.title('Средний Retention Rate пользователей по lifetime')
ax = sns.lineplot(x = retention_rate_mean[1:12].index,
y = retention_rate_mean[1:12])
plt.xlabel('Lifetime')
plt.ylabel('Средний Retention Rate')
plt.show()
Средний коэффициент удержания Retention Rate с течением "жизни" когорт неуклонно снижается, за исключением 11 месяца, где всего одна когорта с самыми активными пользователями, впервые посетившими сайт в июне 2017 года.
# рассчитаем средний Retention Rate по первому месяцу "жизни" когорты
retention_rate_first_mean = cohorts.query('cohort_lifetime == 1')['retention_rate']\
.mean() * 100
d = {'avg_retention_rate_first_pct': retention_rate_first_mean}
retention_metrics_all = pd.DataFrame(data = d,
index = ['all'])
retention_metrics_all
Средний коэффициент удержания Retention Rate по первому месяцу "жизни" когорты составляет 6,52%.
# посчитаем Churn Rate по когортам и lifetime
cohorts['churn_rate'] = cohorts.groupby('first_session_month')['uid']\
.pct_change()
cohorts.head()
# построим сводную таблицу с показателем Churn Rate по когортам и lifetime
churn_rate = cohorts.pivot_table(index = 'first_session_month',
columns = 'cohort_lifetime',
values = 'churn_rate',
aggfunc = 'sum')
churn_rate.fillna('')
# создадим тепловую карту с показателем Churn Rate по когортам и lifetime
plt.figure(figsize = (15, 9))
plt.title('Churn Rate по когортам')
ax = sns.heatmap(churn_rate,
annot = True,
fmt = '.1%',
vmin = -0.6,
vmax = 0.15,
linewidths = 1,
cmap = 'coolwarm',
yticklabels = churn_rate.index.date,
linecolor = 'gray')
plt.xlabel('Lifetime')
plt.ylabel('Когорта')
plt.show()
Более 90% пользователей не возвращаются на сайт в первый месяц "жизни" когорты. В основном показатели Churn Rate отрицательные, положительных значений очень мало, что свидетельствует о том, что случаев возврата пользователей в следующем месяце по сравнению с предыдущим совсем немного. Наибольшее количество положительных значений Churn Rate у когорты пользователей, впервые посетивших сайт в июне 2017 года.
# посмотрим на динамику среднего Churn Rate по времени "жизни" когорты
churn_rate_mean = cohorts.groupby('cohort_lifetime')['churn_rate']\
.mean() * 100
fig, ax = plt.subplots()
plt.title('Средний Churn Rate пользователей по lifetime')
ax = sns.lineplot(x = churn_rate_mean[2:12].index,
y = churn_rate_mean[2:12])
plt.xlabel('Lifetime')
plt.ylabel('Средний Churn Rate')
plt.show()
Средний коэффициент возврата Churn Rate с 3 месяца жизни когорт остается практически неизменным, за исключением 11 месяца, где всего одна когорта с самыми активными пользователями, впервые посетившими сайт в июне 2017 года.
# посмотрим на динамику среднего Retention Rate по времени "жизни" когорты по категориям устройств
cohorts_device = visits.groupby(['device',
'first_session_month',
'cohort_lifetime'])\
.agg({'uid':'nunique'})\
.reset_index()
initial_users_count_device = cohorts_device[cohorts_device['cohort_lifetime'] == 0][['device',
'first_session_month',
'uid']]
initial_users_count_device = initial_users_count_device.rename(columns = {'uid':'cohort_users'})
cohorts_device = cohorts_device.merge(initial_users_count_device,
on = ['device',
'first_session_month'])
cohorts_device['retention_rate'] = cohorts_device['uid'] / cohorts_device['cohort_users']
retention_rate_mean_device = cohorts_device.groupby(['device',
'cohort_lifetime'])['retention_rate']\
.mean() * 100
retention_rate_mean_device = retention_rate_mean_device.reset_index()
fig, ax = plt.subplots()
ax.set(title = 'Средний Retention Rate пользователей по lifetime по категориям устройств',
xlabel = 'Llifetime',
ylabel = 'Средний Retention Rate')
for device in retention_rate_mean_device['device'].unique():
ax.plot(retention_rate_mean_device.query('device == @device')['cohort_lifetime'][1:12],
retention_rate_mean_device.query('device == @device')['retention_rate'][1:12],
label = device )
ax.legend()
plt.show()
Средний коэффициент удержания Retention Rate с течением "жизни" когорт снижается у пользователей и мобильных, и стационарных устройств.
# рассчитаем средний Retention Rate по первому месяцу "жизни" когорты по категориям устройств
retention_metrics_device = retention_rate_mean_device.query('cohort_lifetime == 1')\
.groupby('device')['retention_rate']\
.mean()\
.reset_index()\
.rename(columns = {'retention_rate':'avg_retention_rate_first_pct'})
retention_metrics_device
Средний коэффициент удержания Retention Rate по первому месяцу "жизни" когорты пользователей со стационарными устройствами выше, чем с мобильными (соответственно 6,8% и 6,2%).
# посмотрим на динамику среднего Retention Rate по времени "жизни" когорты по рекламным источникам
cohorts_source = visits.groupby(['source_id',
'first_session_month',
'cohort_lifetime'])\
.agg({'uid':'nunique'})\
.reset_index()
initial_users_count_source = cohorts_source[cohorts_source['cohort_lifetime'] == 0][['source_id',
'first_session_month',
'uid']]
initial_users_count_source = initial_users_count_source.rename(columns = {'uid':'cohort_users'})
cohorts_source = cohorts_source.merge(initial_users_count_source,
on = ['source_id',
'first_session_month'])
cohorts_source['retention_rate'] = cohorts_source['uid'] / cohorts_source['cohort_users']
retention_rate_mean_source = cohorts_source.groupby(['source_id',
'cohort_lifetime'])['retention_rate']\
.mean() * 100
retention_rate_mean_source = retention_rate_mean_source.reset_index()
fig, ax = plt.subplots()
ax.set(title = 'Средний Retention Rate пользователей по lifetime по рекламным источникам',
xlabel = 'Lifetime',
ylabel = 'Средний Retention Rate')
for source in retention_rate_mean_source.query('source_id !=7')['source_id'].unique():
ax.plot(retention_rate_mean_source.query('source_id == @source')['cohort_lifetime'][1:12],
retention_rate_mean_source.query('source_id == @source')['retention_rate'][1:12],
label = source )
ax.legend()
plt.show()
Средний коэффициент удержания Retention Rate с течением "жизни" когорт снижается у пользователей, пришедших на сайт с помощью всех рекламных источников.
# рассчитаем средний Retention Rate по первому месяцу "жизни" когорты по категориям устройств
retention_metrics_source = retention_rate_mean_source.query('cohort_lifetime == 1')\
.groupby('source_id')['retention_rate']\
.mean()\
.reset_index()\
.rename(columns = {'retention_rate':'avg_retention_rate_first_pct'})
retention_metrics_source
Из двух рекламных источников с наибольшим привлечением пользователей - третьего и четвертого - коэффициент удержания Retention Rate по первому месяцу "жизни" когорты у третьего источника очень низок - всего 4,67%. Более 15% пользователей, привлеченных с использованием девятого, второго и первого рекламных источников, возвращаются на сайт в первый месяц "жизни" когорты.
# сведем в одну таблицу все рассчитанные продуктовые метрики
product_metrics_all = pd.concat([visits_metrics_all,
sessions_metrics_all,
asl_metrics_all,
retention_metrics_all],
axis = 1)
product_metrics_all_tr = product_metrics_all.transpose()
product_metrics_all_tr
# сведем в одну таблицу все рассчитанные продуктовые метрики по категориям устройств
product_metrics_device = visits_metrics_device.merge(sessions_metrics_device, on = 'device')\
.merge(asl_metrics_device, on = 'device')\
.merge(retention_metrics_device, on = 'device')
product_metrics_device.set_index('device', inplace = True)
product_metrics_device_tr = product_metrics_device.transpose()
product_metrics_device_tr
# сведем в одну таблицу все рассчитанные продуктовые метрики по рекламным источникам
product_metrics_source = visits_metrics_source.merge(sessions_metrics_source, on = 'source_id')\
.merge(asl_metrics_source, on = 'source_id')\
.merge(retention_metrics_source, on = 'source_id')
product_metrics_source.set_index('source_id', inplace = True)
product_metrics_source_tr = product_metrics_source.transpose()
product_metrics_source_tr
1. Общее количество уникальных пользователей - 228168, среднее количество уникальных пользователей в день - 907, в неделю - 5621, в месяц - 23228, вовлечённость недельной аудитории - 16,15%, месячной - 3,91%. По всей совокупности уникальных пользователей со стационарными устройствами более чем в 2,3 раза больше, чем с мобильными, в связи с чем у них выше и все показатели пользовательской активности. Показатели вовлечённости пользователей у посетителей сайта со стационарных устройств незначительно выше, чем с мобильных. Наибольшее общее количество уникальных пользователей привлечено на сайт при помощи четвертого и третьего рекламных источников, соответственно у этих источников выше и все показатели пользовательской активности. Через шестой и седьмой рекламные источники пользователи практически не привлекались. Показатели вовлечённости аудитории выше у первого и второго рекламных источников. Имеются пользователи, которые для посещения сайта использовали как стационарные, так и мобильные устройства, а также посещали сайт из разных рекламных источников.
2. Динамика количества уникальных пользователей в день очень неравномерна, на графике имеются характерные "зубцы", которые свидетельствуют о разном распределении пользователей по дням недели - в выходные дни количество уникальных пользователей на сайте падает, наибольшее количество таких пользователей по четвергам. Имеется значительный "всплеск" привлечения уникальных пользователей в конце декабря 2017 года, вероятнее всего связанный с новогодними праздниками. Кроме того есть небольшие "всплески" в начале октября 2017 года и середине марта 2018 года. В свою очередь "спад" отмечался в начале августа 2017 года и конце марта 2018 года. Наибольшее количество уникальных пользователей было привлечено на сайт в ноябре 2017 года, после которого их количество неуклонно снижалось, наименьшее - в августе 2017 года.
1. Среднее количество сессий в день - 987, в день на одного пользователя - 1,08. Среднее количество сессий в день у пользователей со стационарными устройствами более чем в 2,7 раза больше, чем с мобильными, а среднее количство сессий в день на одного пользователя у них выше совсем незначительно - всего на 4%. Среднее количество сессий в день наибольшее у пользователей из третьего и четвертого рекламных источников, однако показатели количества сессий в день на одного пользователя иные. Здесь наилучшие значения этого показателя у пользователей из первого источника. У третьего и четвертого рекламных источников, при помощи которых пользователи посещали сайт чаще, количество сессий в день на одного пользователя очень мала.
2. Имеется заметный "всплеск" количества сессий в день в декабре 2017 года, вероятнее всего связанный с новогодними праздниками. Также был небольшой "всплеск" в середине июля 2017 года, середине февраля, ближе к концу марта, в конце мая 2018 года. В то же время в конце марта - начале апреля 2018 года имеется заметный "спад", вероятнее всего связанный с техническими неполадками на сайте. Динамика ежедневного количества сессий, приходящихся на одного пользователя, близка к динамике количества ежедневных сессий с аналогичными "всплесками" и "спадами". Колебания количества сессий в день значительно выше при использовании стационарных устройств, кроме того, ни в один из дней не было превышения случаев использования мобильных устройств для посещения сайта по сравнению со стационарными. В динамике ежедневного количества сессий, приходящихся на одного пользователя, по категориям устройств наблюдаются более значительные колебания этого показателя у пользователей мобильных устройств, кроме того есть дни, когда количество сессий, приходящихся на одного пользователя, выше именно у посетителей сайта из мобильных устройств. Динамика количества сессий в день по рекламным источникам очень похожа, декабрьский "пик" при этом достигнут, в основном, благодаря пользователям, пришедшим из третьего и четвертого рекламных источников. Динамика количества сессий в день на одного пользователя по рекламным источникам подвержена более значительным колебаниям, при этом у первого рекламного источника имеется самое большое количество "всплесков" этого показателя.
Распределение продолжительности сессий очень неравномерно, наибольшее количество сессий с короткой продолжительностью, хотя имеются и весьма продолжительные сессии. По этой причине показателем средней продолжительности сессии ASL будет являться мода, которая равна 60 секундам, в разрезе категорий устройств и рекламных источников значение средней продолжительности сессии ASL соответствует значению этого показателя по всей совокупности за исключением шестого и седьмого рекламных источников, при помощи которых привлечено совсем небольшое количество пользователей.
1. Показатель возврата пользователя к продукту Retention Rate очень низок - ни в один из месяцев "жизни" когорт коэффициент удержания не был выше 10%. Самые активные пользователи - впервые посетившие сайт в июне 2017 года, с течением времени Retention Rate у этой когорты не был менее 4%. Средний коэффициент удержания Retention Rate с течением "жизни" когорт неуклонно снижается, за исключением 11 месяца, где всего одна когорта с самыми активными пользователями, впервые посетившими сайт в июне 2017 года. Средний коэффициент удержания Retention Rate с течением "жизни" когорт снижается у пользователей и по категориям устройств, и по рекламным источникам.
2. Retention Rate в первый месяц "жизни" убывает по когортам, начиная с когорты января 2018 года. Средний коэффициент удержания Retention Rate по первому месяцу "жизни" когорты составляет 6,52%, при этом у пользователей со стационарными устройствами он немного выше, чем у пользователей с мобильными. Из двух рекламных источников с наибольшим привлечением пользователей - третьего и четвертого - коэффициент удержания Retention Rate по первому месяцу "жизни" когорты у третьего источника очень низок - всего 4,67%. Более 15% пользователей, привлеченных с использованием девятого, второго и первого рекламных источников, возвращаются на сайт в первый месяц "жизни" когорты.
3. Более 90% пользователей не возвращаются на сайт в первый месяц "жизни" когорты. В основном показатели Churn Rate отрицательные, положительных значений очень мало, что свидетельствует о том, что случаев возврата пользователей в следующем месяце по сравнению с предыдущим совсем немного. Наибольшее количество положительных значений Churn Rate у когорты пользователей июня 2017 года. Средний коэффициент возврата Churn Rate с 3 месяца жизни когорт остается практически неизменным, за исключением 11 месяца, где всего одна когорта с самыми активными пользователями, впервые посетившими сайт в июне 2017 года.
# определим дату первой покупки пользователями
first_order = orders.groupby('uid')\
.agg({'order_ts':'min'})\
.rename(columns = {'order_ts':'first_order'})\
.reset_index()
first_order.head()
# посчитаем количество строк в полученной таблице
len(first_order)
# добавим в таблицу столбец с первой сессией пользователей
orders_first = first_order.merge(first_session,
on = 'uid')
orders_first.head()
# проверим количество строк в таблице
len(first_order)
# посчитаем время в днях, прошедшее от первой сессии до первой покупки
orders_first['order_session_days'] = (orders_first['first_order'] - orders_first['first_session']).dt.days
orders_first.head()
# посмотрим на распределение количества дней до первой покупки
fig, ax = plt.subplots()
ax.set(title = 'Распределение количества дней до первой покупки',
xlabel = 'Количество дней',
ylabel = 'Количество покупок')
ax.hist(orders_first['order_session_days'],
bins = 100)
plt.show()
Распределение количества дней до первой покупки неравномерно, в основном покупки совершаются достаточно быстро после первого посещения сайта, хотя имеются и весьма продолжительные периоды задержки. В качестве меры центральной тенденции, которая лучше всего отразит количество дней до первой покупки, будем использовать моду.
# рассчитаем моду количества дней до первой покупки
order_session_days_mode = int(orders_first['order_session_days'].mode())
d = {'avg_order_session_days': order_session_days_mode}
order_session_metrics_all = pd.DataFrame(data = d,
index = ['all'])
order_session_metrics_all
В основном первые покупки совершаются пользователями в первый день посещения сайта.
# добавим в таблицу столбец со временем в часах, прошедшим от первой сессии до первой покупки
orders_first['order_session_hours'] = orders_first['first_order'] - orders_first['first_session']
orders_first['order_session_hours'] = (orders_first['order_session_hours'] / np.timedelta64(1,'h')).round(0)\
.astype('int')
orders_first.head()
# посмотрим на распределение количества часов до первой покупки в день первого посещения
fig, ax = plt.subplots()
ax.set(title = 'Распределение количества часов до первой покупки в день первого посещения',
xlabel = 'Количество часов',
ylabel = 'Количество покупок')
ax.hist(orders_first.query('order_session_days == 0')['order_session_hours'],
bins = 50)
plt.show()
В основном первые покупки совершаются пользователями в течение первого часа первого посещения сайта.
# добавим в таблицу столбцы с категориями устройств и идентификаторами рекламных источников
orders_first = orders_first.merge(visits,
on = ['uid',
'first_session'])
orders_first = orders_first.query('first_session == session_start_ts')\
.reset_index()
orders_first = orders_first[['uid',
'device',
'source_id',
'first_order',
'first_session',
'order_session_days',
'order_session_hours']]
orders_first.head()
# проверим количество строк в таблице
len(first_order)
# посмотрим на распределение количества дней до первой покупки по категориям устройств
fig, ax = plt.subplots(figsize=(15, 9))
plt.title('Распределение количества дней до первой покупки по категориям устройств')
ax = sns.boxplot(x = 'device',
y = 'order_session_days',
data = orders_first,
showfliers = False)
plt.xlabel('Категория устройства')
plt.ylabel('Количество дней')
plt.show()
Пользователям мобильных устройств требуется больше времени, чтобы совершить покупку после первого посещения (для 75% пользователей устройств это период до 6 дней). Это может быть связано с неудобством совершения покупки с мобильной версии сайта.
# рассчитаем моду количества дней до первой покупки по категориям устройств
order_session_metrics_device = orders_first.groupby('device')['order_session_days']\
.apply(lambda x: x.mode().iloc[0])\
.reset_index()\
.rename(columns = {'order_session_days':'avg_order_session_days'})
order_session_metrics_device
Показатель среднего количества дней до первой покупки по категориям устройств соответствует общему показателю.
# посмотрим на распределение количества дней до первой покупки по рекламным источникам
fig, ax = plt.subplots(figsize=(15, 9))
plt.title('Распределение количества дней до первой покупки по рекламным источникам')
ax = sns.boxplot(x = 'source_id',
y = 'order_session_days',
data = orders_first,
showfliers = False)
plt.xlabel('Рекламный источник')
plt.ylabel('Количество дней')
plt.show()
Самыми "медленными" являются пользователи, привлеченные на сайт при помощи девятого рекламного источника (для 75% пользователей, пришедших из этого источника, требуется до 70 дней, чтобы совершить покупку после первого посещения). Как ранее было установлено у этого рекламного источника самый высокий средний коэффициент удержания Retention Rate по первому месяцу "жизни" когорты - пользователи возвращаются, чтобы совершить первую покупку.
# рассчитаем моду количества дней до первой покупки по категориям устройств
order_session_metrics_source = orders_first.groupby('source_id')['order_session_days']\
.apply(lambda x: x.mode().iloc[0])\
.reset_index()\
.rename(columns = {'order_session_days':'avg_order_session_days'})
order_session_metrics_source
Показатель среднего количества дней до первой покупки по рекламным источникам соответствует общему показателю.
# посчитаем общую сумму выручки
orders['revenue'].sum()
# добавим в таблицу с заказами столбцы с категориями устройств и идентификаторами рекламных источников
orders = orders.merge(visits,
on = 'uid')
orders = orders.query('first_session == session_start_ts')\
.reset_index()
orders = orders[['uid',
'device',
'source_id',
'revenue',
'order_ts']]
orders.head()
# проверим общую сумму выручки
orders['revenue'].sum()
# добавим в таблицу столбцы с датой, днем недели и месяцем заказа
orders['order_date'] = orders['order_ts'].dt.date
orders['order_month'] = orders['order_ts'].astype('datetime64[M]')
orders['orders_day_of_week'] = orders['order_ts'].dt.weekday
orders.head()
# посмотрим на динамику количества заказов в день
orders_per_day = orders.groupby('order_date')\
.agg({'uid': 'count'})\
.reset_index()
orders_per_day.columns = ['order_date',
'n_orders']
fig, ax = plt.subplots()
plt.title('Динамика количества заказов в день')
ax = sns.lineplot(x = 'order_date',
y = 'n_orders',
data = orders_per_day)
plt.xlabel('Месяц')
plt.ylabel('Количество заказов')
plt.show()
График динамики количества заказов в день также имеет характерные "зубцы", которые вероятнее всего свидетельствуют о разном распределении количества заказов по дням недели.
# посмотрим на количество заказов в день по дням недели
orders_per_day_of_week = orders.groupby('orders_day_of_week')\
.agg({'uid': 'count'})\
.reset_index()
orders_per_day_of_week.columns = ['orders_day_of_week',
'n_orders']
fig, ax = plt.subplots()
plt.title('Количество заказов в день по дням недели')
ax = sns.barplot(x = 'orders_day_of_week',
y = 'n_orders',
data = orders_per_day_of_week)
plt.xlabel('День недели')
plt.ylabel('Количество заказов')
ax.set_xticklabels(labels = day_of_week)
plt.show()
Количество заказов, также, как и количество посещений, в выходные дни снижается.
# посчитаем показатели количества заказов
n_visits = visits['uid'].agg('count')
n_orders = orders['uid'].agg('count')
ratio_orders = n_orders / n_visits * 100
orders_per_day_mean = round(orders_per_day['n_orders'].mean())
d = {'n_visits': n_visits,
'n_orders': n_orders,
'ratio_orders_pct': float(ratio_orders),
'orders_per_day':orders_per_day_mean}
order_metrics_all = pd.DataFrame(data = d,
index = ['all'])
order_metrics_all
Всего 14% посещений сайта связано с осуществлением заказов. В день в среднем осуществлялось 139 заказов.
# посмотрим на динамику количества заказов в месяц
orders_per_month = orders.groupby('order_month')\
.agg({'uid': 'count'})\
.reset_index()
orders_per_month.columns = ['order_month',
'n_orders']
fig, ax = plt.subplots()
plt.title('Динамика количества заказов в месяц')
ax = sns.lineplot(x = 'order_month',
y = 'n_orders',
data = orders_per_month)
plt.xlabel('Месяц')
plt.ylabel('Количество заказов')
plt.show()
Наименьшее количество заказов было осуществлено в августе 2017 года, после чего начался их рост, достигший максимума в декабре 2017 года. После этого количество заказов в месяц то росло, то снижалось.
# посчитаем среднее количество заказов в месяц
order_metrics_all['orders_per_month'] = round(orders_per_month['n_orders'].mean())
order_metrics_all
В месяц в среднем осуществляется 4201 заказ.
# посмотрим на динамику количества заказов в день по категориям устройств
orders_per_day_device = orders.groupby(['device',
'order_date'])\
.agg({'uid': 'count'})\
.reset_index()
orders_per_day_device.columns = ['device',
'order_date',
'n_orders']
fig, ax = plt.subplots()
plt.title('Динамика количества заказов в день по категориям устройств')
ax = sns.lineplot(x = 'order_date',
y = 'n_orders',
data = orders_per_day_device,
hue = 'device')
plt.xlabel('Месяц')
plt.ylabel('Количество заказов')
plt.show()
Количество заказов со стационарных устройств подвержено большим колебаниям, чем с мобильных. Декабрьский "всплеск" количества заказов, вероятнее всего связанный с новогодними праздниками, был достигнут в основном за счет покупателей, использующих стационарные устройства.
# посчитаем показатели количества заказов по категориям устройств
order_metrics_device = visits.groupby('device')\
.agg({'uid': 'count'})\
.reset_index()\
.rename(columns = {'uid':'n_visits'})
buyers_device = orders_per_day_device.groupby('device')\
.agg({'n_orders': 'sum'})\
.reset_index()
order_metrics_device = order_metrics_device.merge(buyers_device,
on = 'device')
order_metrics_device['ratio_orders_pct'] = order_metrics_device['n_orders'] / order_metrics_device['n_visits'] * 100
orders_per_day_device_mean = orders_per_day_device.groupby('device')['n_orders']\
.mean()\
.reset_index()\
.rename(columns = {'n_orders':'orders_per_day'})
orders_per_day_device_mean['orders_per_day'] = round(orders_per_day_device_mean['orders_per_day']).astype('int')
order_metrics_device = order_metrics_device.merge(orders_per_day_device_mean,
on = 'device')
order_metrics_device
Более 15% посещений сайта со стационарных устройств связано с осуществлением заказов. У пользователей мобильных устройств "холостых" посещений значительно больше (заказы осуществляются менее, чем в 10% посещений). Среднее количество заказов в день более чем в 4 раза больше у покупателей со стационарными устройствами.
# посмотрим на динамику количества заказов в месяц по категориям устройств
orders_per_month_device = orders.groupby(['device',
'order_month'])\
.agg({'uid': 'count'})\
.reset_index()
orders_per_month_device.columns = ['device',
'order_month',
'n_orders']
fig, ax = plt.subplots()
plt.title('Динамика количества заказов в месяц по категориям устройств')
ax = sns.lineplot(x = 'order_month',
y = 'n_orders',
data = orders_per_month_device,
hue = 'device')
plt.xlabel('Месяц')
plt.ylabel('Количество заказов')
plt.show()
Количество заказов в месяц у пользователей стационарных устройств подвержено большим колебаниям, тогда как количество заказов у пользователей мобильных устройств из месяца в месяц практически не меняется.
# посчитаем среднее количество заказов в месяц по категориям устройств
orders_per_month_device_mean = orders_per_month_device.groupby('device')['n_orders']\
.mean()\
.reset_index()\
.rename(columns = {'n_orders':'orders_per_month'})
orders_per_month_device_mean['orders_per_month'] = round(orders_per_month_device_mean['orders_per_month']).astype('int')
order_metrics_device = order_metrics_device.merge(orders_per_month_device_mean,
on = 'device')
order_metrics_device
Среднее количество заказов в месяц также более чем в 4 раза больше у покупателей со стационарными устройствами.
# посмотрим на динамику количества заказов в день по рекламным источникам
orders_per_day_source = orders.groupby(['source_id',
'order_date'])\
.agg({'uid': 'count'})\
.reset_index()
orders_per_day_source.columns = ['source_id',
'order_date',
'n_orders']
orders_per_day_source
fig, ax = plt.subplots(figsize = (18, 12))
ax.set(title = 'Динамика количества заказов в день по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Количество заказов')
for source in orders_per_day_source['source_id'].unique():
ax.plot(orders_per_day_source.query('source_id == @source')['order_date'],
orders_per_day_source.query('source_id == @source')['n_orders'],
label = source)
ax.legend()
plt.show()
Больше всего заказов осуществляется пользователями, посетившими сайт при помощи четвертого и третьего рекламного источника. Декабрьский "всплеск" количества заказов, вероятнее всего связанный с новогодними праздниками, был обеспечен в основном именно этими источниками.
# посчитаем показатели количества заказов по рекламным источникам
order_metrics_source = visits.groupby('source_id')\
.agg({'uid': 'count'})\
.reset_index()\
.rename(columns = {'uid':'n_visits'})
buyers_source = orders_per_day_source.groupby('source_id')\
.agg({'n_orders': 'sum'})\
.reset_index()
order_metrics_source = order_metrics_source.merge(buyers_source,
on = 'source_id')
order_metrics_source['ratio_orders_pct'] = order_metrics_source['n_orders'] / order_metrics_source['n_visits'] * 100
orders_per_day_source_mean = orders_per_day_source.groupby('source_id')['n_orders']\
.mean()\
.reset_index()\
.rename(columns = {'n_orders':'orders_per_day'})
orders_per_day_source_mean['orders_per_day'] = round(orders_per_day_source_mean['orders_per_day']).astype('int')
order_metrics_source = order_metrics_source.merge(orders_per_day_source_mean,
on = 'source_id')
order_metrics_source
У пользователей, посетивших сайт при помощи первого, третьего и десятого рекламных источников, более 15% посещений сайта связано с осуществлением заказов. У седьмого источника лишь одно посещение из 36 привело к осуществлению заказа. Наибольшее среднее количество заказов в день у покупателей, пришедших из третьего и четвертого рекламных источников.
# посмотрим на динамику количества заказов в месяц по по рекламным источникам
orders_per_month_source = orders.groupby(['source_id',
'order_month'])\
.agg({'uid': 'count'})\
.reset_index()
orders_per_month_source.columns = ['source_id',
'order_month',
'n_orders']
fig, ax = plt.subplots()
ax.set(title = 'Динамика количества заказов в месяц по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Количество заказов')
for source in orders_per_month_source['source_id'].unique():
ax.plot(orders_per_month_source.query('source_id == @source')['order_month'],
orders_per_month_source.query('source_id == @source')['n_orders'],
label = source)
ax.legend()
plt.show()
У самых популярных рекламных источников (третьего и четвертого) рост количества заказов начался с сентября 2017 года, до этого они практически не выделялись на фоне других источников.
# посчитаем среднее количество заказов в месяц по категориям устройств
orders_per_month_source_mean = orders_per_month_source.groupby('source_id')['n_orders']\
.mean()\
.reset_index()\
.rename(columns = {'n_orders':'orders_per_month'})
orders_per_month_source_mean['orders_per_month'] = round(orders_per_month_source_mean['orders_per_month']).astype('int')
order_metrics_source = order_metrics_source.merge(orders_per_month_source_mean,
on = 'source_id')
order_metrics_source
Наибольшее среднее количество заказов в месяц также у покупателей, пришедших из третьего и четвертого рекламных источников.
# найдем покупателей, принесших наибольшую выручку
top_buyers = orders.groupby('uid')['revenue']\
.sum()\
.sort_values(ascending = False)\
.head(10)
top_buyers
# посчитаем долю выручки от двух самых ценных покупателей
(top_buyers.head(2).sum() / orders['revenue'].sum() * 100).round(1)
Два покупателя принесли 8,9% всей выручки.
# определим категории устройств и рекламные источники самых ценных покупателей
orders.query('uid == "5539673724080479777" or uid == "11149926373378902217"')\
.groupby(['device',
'source_id',
'order_month'])['revenue']\
.sum()
Самые ценные покупатели использовали стационарные устройства, стали пользователями сайта при помощи второго и пятого рекламных источников. Один из покупателей впервые совершил заказ в декабре 2017 года, второй - в сентябре 2017 года. Эти выбивающиеся значения выручки могут повлиять на дальнейшее исследование. Как уже ранее отмечалось, вероятнее всего это корпоративные клиенты, покупавшие билеты для своих работников, либо перекупщики билетов, решившие заработать на наиболее популярных мероприятиях (самые большие суммы этими покупателями потрачены в декабре - Новый год, феврале - 23 февраля, марте - 8 марта).
# посчитаем показатели выручки
total_revenue = orders['revenue'].agg('sum')
mean_revenue = orders['revenue'].agg('mean')
median_revenue = orders['revenue'].agg('median')
n_buyers = orders['uid'].agg('nunique')
orders_per_buyers = n_orders / n_buyers
d = {'total_revenue': total_revenue,
'avg_fee': mean_revenue,
'median_fee': median_revenue,
'n_buyers':n_buyers,
'orders_per_buyers':orders_per_buyers}
revenue_metrics_all = pd.DataFrame(data = d,
index = ['all'])
revenue_metrics_all
Общая выручка составила 252053,78 рублей, средний чек - 5 рублей, медианный в 2 раза ниже - 2,5 рубля. Общее количество покупателей - 36522, в среднем один покупатель совершал 1,38 заказа.
# посмотрим на динамику среднего чека в день
revenue_per_day = orders.groupby('order_date')\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_day.columns = ['order_date',
'revenue',
'n_orders']
revenue_per_day['avg_fee'] = revenue_per_day['revenue'] / revenue_per_day['n_orders']
fig, ax = plt.subplots()
plt.title('Динамика среднего чека в день')
ax = sns.lineplot(x = 'order_date',
y = 'avg_fee',
data = revenue_per_day)
plt.xlabel('Месяц')
plt.ylabel('Средний чек, рублей')
plt.show()
Есть дни с очень высокими значениями среднего чека, вероятнее всего это связано с разовыми крупными покупками в эти дни. График динамики среднего чека имеет характерные "зубцы", которые вероятнее всего свидетельствуют о его разном распределении по дням недели. Кроме того заметен рост среднего чека перед праздничными днями.
# посмотрим на средний чек по дням недели
revenue_per_day_of_week = orders.groupby('orders_day_of_week')\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_day_of_week.columns = ['orders_day_of_week',
'revenue',
'n_orders']
revenue_per_day_of_week['avg_fee'] = revenue_per_day_of_week['revenue'] / revenue_per_day_of_week['n_orders']
fig, ax = plt.subplots()
plt.title('Средний чек по дням недели')
ax = sns.barplot(x = 'orders_day_of_week',
y = 'avg_fee',
data = revenue_per_day_of_week)
plt.xlabel('День недели')
plt.ylabel('Средний чек, рублей')
ax.set_xticklabels(labels = day_of_week)
plt.show()
Самый низкий средний чек по субботам, а самый высокий - по воскресеньям (день с самым маленьким количеством заказов).
# посмотрим на динамику среднего чека в месяц
revenue_per_month = orders.groupby('order_month')\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_month.columns = ['order_month',
'revenue',
'n_orders']
revenue_per_month['avg_fee'] = revenue_per_month['revenue'] / revenue_per_month['n_orders']
fig, ax = plt.subplots()
plt.title('Динамика среднего чека в месяц')
ax = sns.lineplot(x = 'order_month',
y = 'avg_fee',
data = revenue_per_month)
plt.xlabel('Месяц')
plt.ylabel('Средний чек, рублей')
plt.show()
Самый высокий средний чек в декабре 2017 года, самый низкий - в июне 2017 года и январе 2018 года (сразу после резкого роста).
# посчитаем показатели выручки по категориям устройств
revenue_metrics_device = orders.groupby('device')\
.agg({'revenue':['sum', 'mean', 'median'], 'uid':'nunique'})\
.reset_index()
revenue_metrics_device.columns = ['device',
'total_revenue',
'avg_fee',
'median_fee',
'n_buyers']
revenue_metrics_device['orders_per_buyers'] = order_metrics_device['n_orders'] / revenue_metrics_device['n_buyers']
revenue_metrics_device
Общая выручка от покупателей со стационарными устройствами в 5 раз больше выручки от покупателей с мобильными устройствами. Средний и медианный чек, а также количество покупателей и среднее количество заказов на одного покупателя также выше у пользователей, заходящих на сайт со стационарных устройств.
# посмотрим на динамику среднего чека в день по категориям устройств
revenue_per_day_device = orders.groupby(['device',
'order_date'])\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_day_device.columns = ['device',
'order_date',
'revenue',
'n_orders']
revenue_per_day_device['avg_fee'] = revenue_per_day_device['revenue'] / revenue_per_day_device['n_orders']
fig, ax = plt.subplots()
plt.title('Динамика среднего чека в день по категориям устройств')
ax = sns.lineplot(x = 'order_date',
y = 'avg_fee',
data = revenue_per_day_device,
hue = 'device')
plt.xlabel('Месяц')
plt.ylabel('Средний чек, рублей')
plt.show()
Средний чек пользователей, заходящих на сайт со стационарных устройств, выше, чем у испольующих мобильные устройства, в основном за счет нескольких дней с весьма высокими значениями среднего чека.
# посмотрим на динамику среднего чека в месяц по категориям устройств
revenue_per_month_device = orders.groupby(['device',
'order_month'])\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_month_device.columns = ['device',
'order_month',
'revenue',
'n_orders']
revenue_per_month_device['avg_fee'] = revenue_per_month_device['revenue'] / revenue_per_month_device['n_orders']
revenue_per_month_device
fig, ax = plt.subplots()
plt.title('Динамика среднего чека в месяц по категориям устройств')
ax = sns.lineplot(x = 'order_month',
y = 'avg_fee',
data = revenue_per_month_device,
hue = 'device')
plt.xlabel('Месяц')
plt.ylabel('Средний чек, рублей')
plt.show()
Только в ноябре 2017 года средний чек пользователей с мобильными устройствами был выше, чем у пользователей со стационарными устройствами. Средний чек декабря 2017 года у покупателей с разными устройствами находится на разных "полюсах".
# посчитаем показатели выручки по рекламным источникам
revenue_metrics_source = orders.groupby('source_id')\
.agg({'revenue':['sum', 'mean', 'median'], 'uid':'nunique'})\
.reset_index()
revenue_metrics_source.columns = ['source_id',
'total_revenue',
'avg_fee',
'median_fee',
'n_buyers']
revenue_metrics_source['orders_per_buyers'] = order_metrics_source['n_orders'] / revenue_metrics_source['n_buyers']
revenue_metrics_source
Самая большая выручка от покупателей, привлеченных на сайт при помощи четвертого, третьего и пятого рекламных источников, однако самый высокий средний чек от пользователей, пришедших из второго рекламного источника. В то же время, у этого рекламного источника медианный чек не самый высокий из-за присутствия в группе одного из самых "ценных" покупателей. Наибольшее количество покупателей пришли с помощью третьего и четвертого рекламных источников, однако самые высокие показатели среднего количества заказов на одного покупателя у второго и первого рекламных источников.
# посмотрим на динамику среднего чека в день по рекламным источникам
revenue_per_day_source = orders.groupby(['source_id',
'order_date'])\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_day_source.columns = ['source_id',
'order_date',
'revenue',
'n_orders']
revenue_per_day_source['avg_fee'] = revenue_per_day_source['revenue'] / revenue_per_day_source['n_orders']
fig, ax = plt.subplots(figsize = (18, 12))
ax.set(title = 'Динамика среднего чека в день по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Средний чек, рублей')
for source in revenue_per_day_source['source_id'].unique():
ax.plot(revenue_per_day_source.query('source_id == @source')['order_date'],
revenue_per_day_source.query('source_id == @source')['avg_fee'],
label = source)
ax.legend()
plt.show()
У пятого рекламного источника в один из дней декабря 2017 года есть очень высокое значение среднего чека, вероятнее всего связанное с разовой крупной покупкой. Наибольшее количество "пиковых" дней с высокими значениями среднего чека у второго рекламного источника.
# посмотрим на динамику среднего чека в месяц по рекламным источникам
revenue_per_month_source = orders.groupby(['source_id',
'order_month'])\
.agg({'revenue': ['sum', 'count']})\
.reset_index()
revenue_per_month_source.columns = ['source_id',
'order_month',
'revenue',
'n_orders']
revenue_per_month_source['avg_fee'] = revenue_per_month_source['revenue'] / revenue_per_month_source['n_orders']
fig, ax = plt.subplots()
ax.set(title = 'Динамика среднего чека в месяц по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Средний чек, рублей')
for source in revenue_per_month_source['source_id'].unique():
ax.plot(revenue_per_month_source.query('source_id == @source')['order_month'],
revenue_per_month_source.query('source_id == @source')['avg_fee'],
label = source)
ax.legend()
plt.show()
Средний чек в месяц практически по всем рекламным источникам из месяца в месяц меняется незначительно, за исключением пятого источника с большим значением среднего чека в декабре 2017 года, и второго источника с "всплеском" в феврале - марте 2018 года. Как уже отмечалось ранее в эти месяцы свои самые крупные покупки совершали наиболее "ценные" покупатели.
У нас отсутствует информация о маржинальности продаж, следовательно будем считать, что валовая прибыль равна выручке. Предположим, что Яндекс.Афиша получает фиксированный доход (или процент) от продаж, не неся каких-либо затрат (т.е. с нулевой себестоимостью).
# в таблицу с датой первого заказа добавим столбец с месяцем первого заказа
first_order['first_order_month'] = first_order['first_order'].astype('datetime64[M]')
first_order.head()
# определим исходное количество покупателей в когортах
cohort_sizes = first_order.groupby('first_order_month')\
.agg({'uid': 'nunique'})\
.reset_index()
cohort_sizes.columns = ['first_order_month',
'n_buyers']
cohort_sizes
# в таблицу с заказами добавим сведения о месяце первого заказа
orders = orders.merge(first_order,
on = 'uid')
orders.head()
# проверим общую сумму выручки
orders['revenue'].sum()
# сформируем когорты покупателей по месяцу первого заказа
cohorts_orders = orders.groupby(['first_order_month',
'order_month'])\
.agg({'revenue': 'sum'})\
.reset_index()
cohorts_orders.head()
# добавим в таблицу столбец с количеством покупателей в когортах
report = cohort_sizes.merge(cohorts_orders,
on = 'first_order_month')
report.head()
# проверим общую сумму выручки
report['revenue'].sum()
# добавим в таблицу столбец с lifetime покупателей и посчитаем LTV по когортам и lifetime
report['cohort_lifetime'] = ((report['order_month'] - report['first_order_month']) / np.timedelta64(1, 'M')).round()\
.astype('int')
report['ltv'] = report['revenue'] / report['n_buyers']
report.head()
# построим сводную таблицу с показателем LTV по когортам и lifetime
ltv = report.pivot_table(index = 'first_order_month',
columns = 'cohort_lifetime',
values = 'ltv',
aggfunc = 'mean')\
.round(2)
ltv.fillna('')
# создадим тепловую карту с показателем LTV по когортам и lifetime
plt.figure(figsize = (15, 9))
plt.title('LTV по когортам')
ax = sns.heatmap(ltv,
annot = True,
fmt = '.2f',
linewidths = 1,
cmap = 'coolwarm',
linecolor = 'gray',
yticklabels = ltv.index.date)
plt.xlabel('Lifetime')
plt.ylabel('Когорта')
plt.show()
Для всех когорт лучший показатель ценности клиента LTV - в месяц совершения первого заказа. В дальнейшем показатель LTV лишь изредка превышал 1 рубль. У когорты сентября 2017 года есть значительный "всплеск" в третий месяц ее "жизни", вероятнее всего связанный с крупными разовыми покупками в декабре 2017 года.
# посмотрим на динамику среднего LTV по времени "жизни" когорты без учета ее нулевого месяца
ltv_mean = report.groupby('cohort_lifetime')['ltv']\
.mean()\
.reset_index()
fig, ax = plt.subplots()
plt.title('Средний LTV когорт по lifetime')
ax = sns.lineplot(x = ltv_mean['cohort_lifetime'][1:12],
y = ltv_mean['ltv'][1:12])
plt.xlabel('Lifetime')
plt.ylabel('Средний LTV, рублей')
plt.show()
Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" с течением "жизни" когорт неуклонно снижается, за исключением 3 месяца, когда произошел значительный "всплеск" у когорты сентября 2017 года.
# рассчитаем средний LTV по нулевому месяцу "жизни" когорты
ltv_null_mean = report.query('cohort_lifetime == 0')['ltv'].mean()
d = {'avg_ltv_null': ltv_null_mean}
ltv_metrics_all = pd.DataFrame(data = d,
index = ['all'])
ltv_metrics_all
Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты составляет 4,92 рубля.
# построим сводную таблицу с показателем накопительного LTV по когортам и lifetime
ltv_cumsum = ltv.cumsum(axis = 1)
ltv_cumsum.fillna('')
# создадим тепловую карту с показателем накопительного LTV по когортам и lifetime
plt.figure(figsize = (15, 9))
plt.title('Накопительный LTV по когортам')
ax = sns.heatmap(ltv_cumsum,
annot = True,
fmt = '.2f',
linewidths = 1,
cmap = 'coolwarm',
linecolor = 'gray',
yticklabels = ltv.index.date)
plt.xlabel('Lifetime')
plt.ylabel('Когорта')
plt.show()
Наибольшая средняя выручка с одного покупателя (13,43 рубля) - у когорты сентября 2017 года, в которую входит один из двух самых "ценных" покупателей. Хороший накопительный LTV и у самой "старой" когорты - июня 2017 года (11,88 рублей).
# посмотрим на накопительный LTV по когортам
ltv_sum = report.groupby('first_order_month')['ltv']\
.sum()\
.reset_index()
fig, ax = plt.subplots()
plt.title('Накопительный LTV по когортам')
ax = sns.barplot(x = 'first_order_month',
y = 'ltv',
data = ltv_sum)
ax.set_xticklabels(labels = ltv_sum['first_order_month'].dt.strftime('%Y-%m-%d'),
fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('Накопительный LTV, рублей')
ax.grid = True
plt.show()
Чем моложе когорта, тем меньше средняя выручка с одного покупателя. Эту тенденцию нарушают покупатели когорт сентября и декабря 2017 года, в которые входят самые ценные клиенты.
# посчитаем средний LTV по всем покупателям
ltv_metrics_all['avg_ltv'] = revenue_metrics_all['total_revenue'].sum() / revenue_metrics_all['n_buyers'].sum()
ltv_metrics_all
Средняя выручка с одного покупателя - 6,9 рублей.
# посмотрим на динамику среднего LTV по времени "жизни" когорты по категориям устройств без учета ее нулевого месяца
cohort_sizes_device = orders.groupby(['device',
'first_order_month'])\
.agg({'uid':'nunique'})\
.reset_index()
cohort_sizes_device.columns = ['device',
'first_order_month',
'n_buyers']
cohorts_orders_device = orders.groupby(['device',
'first_order_month',
'order_month'])\
.agg({'revenue': 'sum'})\
.reset_index()
report_device = cohort_sizes_device.merge(cohorts_orders_device,
on = ['device',
'first_order_month'])
report_device['cohort_lifetime'] = ((report_device['order_month'] - report_device['first_order_month'])\
/ np.timedelta64(1, 'M')).round().astype('int')
report_device['ltv'] = report_device['revenue'] / report_device['n_buyers']
ltv_mean_device = report_device.groupby(['device',
'cohort_lifetime'])['ltv']\
.mean()\
.reset_index()
fig, ax = plt.subplots()
ax.set(title = 'Средний LTV когорт по lifetime по категориям устройств',
xlabel = 'Lifetime',
ylabel = 'Средний LTV, рублей')
for device in ltv_mean_device['device'].unique():
ax.plot(ltv_mean_device.query('device == @device')['cohort_lifetime'][1:12],
ltv_mean_device.query('device == @device')['ltv'][1:12],
label = device )
ax.legend()
plt.show()
Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" у пользователей с мобильными устройствами в течение "жизни" когорт снижается медленнее, чем у пользователей со стационарными устройствами.
# проверим общую сумму выручки
report_device['revenue'].sum()
# рассчитаем средний LTV по нулевому месяцу "жизни" когорты по категориям устройств
ltv_metrics_device = report_device.query('cohort_lifetime == 0')\
.groupby('device')['ltv']\
.mean()\
.reset_index()\
.rename(columns = {'ltv':'avg_ltv_null'})
ltv_metrics_device
Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты выше у пользователей со стационарными устройствами.
# посмотрим на накопительный LTV по когортам по категориям устройств
ltv_sum_device = report_device.groupby(['device',
'first_order_month'])['ltv']\
.sum()\
.reset_index()
fig, ax = plt.subplots()
plt.title('Накопительный LTV по когортам')
ax = sns.barplot(x = 'first_order_month',
y = 'ltv',
data = ltv_sum_device,
hue = 'device')
ax.set_xticklabels(labels = ltv_sum_device['first_order_month'].dt.strftime('%Y-%m-%d'),
fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('Накопительный LTV, рублей')
plt.show()
Только у когорты покупателей марта 2018 года средняя выручка с одного покупателя выше у пользователей с мобильными устройствами.
# посчитаем средний LTV по всем покупателям по категориям устройств
f = revenue_metrics_device.groupby('device')['total_revenue'].sum()\
/ revenue_metrics_device.groupby('device')['n_buyers'].sum()
ltv_metrics_device['avg_ltv'] = ltv_metrics_device['device'].apply(lambda x: f[x])
ltv_metrics_device
Средняя выручка с одного покупателя по категориям устройств значительно выше у покупателей со стационарными устройствами.
# посмотрим на динамику среднего LTV по времени "жизни" когорты по рекламным источникам без учета ее нулевого месяца
cohort_sizes_source = orders.groupby(['source_id',
'first_order_month'])\
.agg({'uid':'nunique'})\
.reset_index()
cohort_sizes_source.columns = ['source_id',
'first_order_month',
'n_buyers']
cohorts_orders_source = orders.groupby(['source_id',
'first_order_month',
'order_month'])\
.agg({'revenue': 'sum'})\
.reset_index()
report_source = cohort_sizes_source.merge(cohorts_orders_source,
on = ['source_id',
'first_order_month'])
report_source['cohort_lifetime'] = ((report_source['order_month'] - report_source['first_order_month'])\
/ np.timedelta64(1, 'M')).round().astype('int')
report_source['ltv'] = report_source['revenue'] / report_source['n_buyers']
ltv_mean_source = report_source.groupby(['source_id',
'cohort_lifetime'])['ltv']\
.mean()\
.reset_index()
fig, ax = plt.subplots()
ax.set(title = 'Средний LTV когорт по lifetime по рекламным источникам',
xlabel = 'Lifetime',
ylabel = 'Средний LTV, рублей')
for source in ltv_mean_source['source_id'].unique():
ax.plot(ltv_mean_source.query('source_id == @source')['cohort_lifetime'][1:12],
ltv_mean_source.query('source_id == @source')['ltv'][1:12],
label = source )
ax.legend()
plt.show()
Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" в течение "жизни" когорт растет только у покупателей, пришедших на сайт с помощью первого рекламного источника.
# проверим общую сумму выручки
report_source['revenue'].sum()
# рассчитаем средний LTV по нулевому месяцу "жизни" когорты по рекламным источникам
ltv_metrics_source = report_source.query('cohort_lifetime == 0')\
.groupby('source_id')['ltv']\
.mean()\
.reset_index()\
.rename(columns = {'ltv':'avg_ltv_null'})
ltv_metrics_source
Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты самый высокий у покупателей, посетивших сайт при помощи второго и первого рекламных источников.
# посмотрим на накопительный LTV по когортам по рекламным источникам
ltv_sum_source = report_source.groupby(['source_id',
'first_order_month'])['ltv']\
.sum()\
.reset_index()
fig, ax = plt.subplots()
plt.title('Накопительный LTV по когортам по рекламным источникам')
ax = sns.barplot(x = 'first_order_month',
y = 'ltv',
data = ltv_sum_source,
hue = 'source_id')
ax.set_xticklabels(labels = ltv_sum_source['first_order_month'].dt.strftime('%Y-%m-%d'),
fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('Накопительный LTV, рублей')
ax.grid = True
plt.show()
У разных когорт разные "лидеры" среди рекламных источников по уровню средней выручки с одного покупателя - либо первый, либо второй рекламные источники.
# посчитаем средний LTV по всем покупателям по рекламным источникам
f = revenue_metrics_source.groupby('source_id')['total_revenue'].sum()\
/ revenue_metrics_source.groupby('source_id')['n_buyers'].sum()
ltv_metrics_source['avg_ltv'] = ltv_metrics_source['source_id'].apply(lambda x: f[x])
ltv_metrics_source
Средняя выручка с одного покупателя самая высокая от покупателей, пришедших из второго (13,38 рублей) и первого (10,72 рублей) рекламных источников, самая низкая - от покупателей, пришедших из десятого (3,35 рублей) источника. Покупатели, пришедшие из второго рекламного источника, более половины выручки приносят после нулевого месяца "жизни" когорт.
# сведем в одну таблицу все рассчитанные торговые метрики
trading_metrics_all = pd.concat([order_session_metrics_all,
order_metrics_all,
revenue_metrics_all,
ltv_metrics_all],
axis = 1)
trading_metrics_all_tr = trading_metrics_all.transpose()
trading_metrics_all_tr
# сведем в одну таблицу все рассчитанные торговые метрики по категориям устройств
trading_metrics_device = order_session_metrics_device.merge(order_metrics_device,
on = 'device')\
.merge(revenue_metrics_device,
on = 'device')\
.merge(ltv_metrics_device,
on = 'device')
trading_metrics_device.set_index('device', inplace = True)
trading_metrics_device_tr = trading_metrics_device.transpose()
trading_metrics_device_tr
# сведем в одну таблицу все рассчитанные торговые метрики по рекламным источникам
trading_metrics_source = order_session_metrics_source.merge(order_metrics_source,
on = 'source_id')\
.merge(revenue_metrics_source,
on = 'source_id')\
.merge(ltv_metrics_source,
on = 'source_id')
trading_metrics_source.set_index('source_id', inplace = True)
trading_metrics_source_tr = trading_metrics_source.transpose()
trading_metrics_source_tr
1. Распределение количества дней до первой покупки неравномерно, в основном покупки совершаются достаточно быстро после первого посещения сайта, хотя имеются и весьма продолжительные периоды задержки. По этой причине показателем, который лучше всего отразит среднее количество дней до первой покупки, будет являться мода, которая равна 0 дней, в разрезе категорий устройств и рекламных источников значение среднего количества дней до первой покупки соответствует значению этого показателя по всей совокупности.
2. Таким образом, в основном первые покупки совершаются пользователями в первый день посещения сайта. Мало того, первые покупки совершаются пользователями в основном в течение первого часа первого посещения сайта. Пользователям мобильных устройств требуется больше времени, чтобы совершить покупку после первого посещения (для 75% пользователей устройств это период до 6 дней). Среди рекламных источников самыми "медленными" являются пользователи, привлеченные на сайт при помощи девятого источника (для 75% пользователей, пришедших из этого источника, требуется до 70 дней, чтобы совершить покупку после первого посещения). Как ранее было установлено у этого рекламного источника самый высокий средний коэффициент удержания Retention Rate по первому месяцу "жизни" когорты, то есть пользователи возвращаются, чтобы совершить первую покупку.
1. Всего из 359399 посещений сайта заказы были осуществлены в 50414 случаях, что составило чуть более 14%. Более 15% посещений сайта со стационарных устройств связано с осуществлением заказов, у пользователей мобильных устройств "холостых" посещений значительно больше (заказы осуществлялись менее, чем в 10% посещений). У пользователей, посетивших сайт при помощи первого, третьего и десятого рекламных источников, более 15% посещений сайта связано с осуществлением заказов, у седьмого источника лишь одно посещение из 36 привело к осуществлению заказа. Среднее количество заказов в день - 139, в месяц - 4201. У покупателей со стационарными устройствами эти показатели более чем в 4 раза выше, чем у покупателей с мобильными. Самые высокие значения среднего количество заказов в день и месяц у покупателей, пришедших из третьего и четвертого рекламных источников.
2. График динамики количества заказов в день также имеет характерные "зубцы", которые свидетельствуют о разном распределении количества заказов по дням недели - количество заказов, также, как и количество посещений, в выходные дни снижается. Наименьшее количество заказов было осуществлено в августе 2017 года, после чего начался их рост, достигший максимума в декабре 2017 года. После этого количество заказов в месяц то росло, то снижалось. Количество заказов в день со стационарных устройств подвержено большим колебаниям, чем с мобильных. Декабрьский "всплеск" количества заказов, вероятнее всего связанный с новогодними праздниками, был достигнут в основном за счет покупателей, использующих стационарные устройства. Количество заказов в месяц у пользователей стационарных устройств также подвержено большим колебаниям, тогда как количество заказов у пользователей мобильных устройств из месяца в месяц практически не меняется. У самых популярных рекламных источников (третьего и четвертого) рост количества заказов начался с сентября 2017 года, до этого они практически не выделялись на фоне других источников. Декабрьский "всплеск" количества заказов, вероятнее всего связанный с новогодними праздниками, был обеспечен в основном именно этими источниками.
1. Общая выручка составила 252053,78 рублей, средний чек - 5 рублей, медианный в 2 раза ниже - 2,5 рубля. Общее количество покупателей - 36522, в среднем один покупатель совершал 1,38 заказа. Два покупателя принесли 8,9% всей выручки. Самые ценные покупатели использовали стационарные устройства, стали пользователями сайта при помощи второго и пятого рекламных источников. Один из покупателей впервые совершил заказ в декабре 2017 года, второй - в сентябре 2017 года. Эти выбивающиеся значения выручки могут повлиять на дальнейшее исследование. Вероятнее всего это корпоративные клиенты, покупавшие билеты для своих работников, либо перекупщики билетов, решившие заработать на наиболее популярных мероприятиях (самые большие суммы этими покупателями потрачены в декабре - Новый год, феврале - 23 февраля, марте - 8 марта). Общая выручка от покупателей со стационарными устройствами в 5 раз больше выручки от покупателей с мобильными устройствами. Средний и медианный чек, а также количество покупателей и среднее количество заказов на одного покупателя также выше у пользователей, приходящих на сайт со стационарных устройств. Средний чек пользователей, заходящих на сайт со стационарных устройств, выше, чем у использующих мобильные устройства, в основном за счет нескольких дней с весьма высокими значениями среднего чека. Самая большая выручка от покупателей, привлеченных на сайт при помощи четвертого, третьего и пятого рекламных источников, однако самый высокий средний чек от пользователей, пришедших из второго рекламного источника. В то же время, у этого рекламного источника медианный чек не самый высокий из-за присутствия в группе одного из самых "ценных" покупателей. Наибольшее количество покупателей пришли с помощью третьего и четвертого рекламных источников, однако самые высокие показатели среднего количества заказов на одного покупателя у второго и первого рекламных источников.
2. Есть дни с очень высокими значениями среднего чека, вероятнее всего это связано с разовыми крупными покупками в эти дни. График динамики среднего чека имеет характерные "зубцы", которые свидетельствуют о его разном распределении по дням недели - самый низкий средний чек по субботам, а самый высокий - по воскресеньям (день с самым маленьким количеством заказов). Кроме того заметен рост среднего чека перед праздничными днями. Самый высокий средний чек в декабре 2017 года, самый низкий - в июне 2017 года и январе 2018 года (сразу после резкого роста). Только в ноябре 2017 года средний чек пользователей с мобильными устройствами был выше, чем у пользователей со стационарными устройствами. Средний чек декабря 2017 года у покупателей с разными устройствами находится на разных "полюсах". У пятого рекламного источника в один из дней декабря 2017 года есть очень высокое значение среднего чека, вероятнее всего связанное с разовой крупной покупкой. Наибольшее количество "пиковых" дней с высокими значениями среднего чека у второго рекламного источника. Средний чек в месяц практически по всем рекламным источникам из месяца в месяц меняется незначительно, за исключением пятого источника с большим значением среднего чека в декабре 2017 года, и второго источника с "всплеском" в феврале - марте 2018 года. Как уже отмечалось ранее в эти месяцы свои самые крупные покупки совершали наиболее "ценные" покупатели.
1. У нас отсутствует информация о маржинальности продаж, следовательно будем считать, что валовая прибыль равна выручке.
Предположим, что Яндекс.Афиша получает фиксированный доход (или процент) от продаж, не неся каких-либо затрат (т.е. с нулевой себестоимостью). Для всех когорт лучший показатель ценности клиента LTV - в месяц совершения первого заказа. В дальнейшем показатель LTV лишь изредка превышал 1 рубль. У когорты сентября 2017 года есть значительный "всплеск" в третий месяц ее "жизни", вероятнее всего связанный с крупными разовыми покупками в декабре 2017 года. Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" с течением "жизни" когорт неуклонно снижается, за исключением 3 месяца, когда произошел значительный "всплеск" у когорты сентября 2017 года. Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты составляет 4,92 рубля. Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" у пользователей с мобильными устройствами в течение "жизни" когорт снижается медленнее, чем у пользователей со стационарными устройствами. Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты выше у пользователей со стационарными устройствами. Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" в течение "жизни" когорт растет только у покупателей, пришедших на сайт с помощью первого рекламного источника. Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты самый высокий у покупателей, посетивших сайт при помощи второго и первого рекламных источников.
2. Наибольшая средняя выручка с одного покупателя (13,43 рубля) - у когорты сентября 2017 года, в которую входит один из двух самых "ценных" покупателей. Хороший накопительный LTV и у самой "старой" когорты - июня 2017 года (11,88 рублей).
Чем моложе когорта, тем меньше средняя выручка с одного покупателя. Эту тенденцию нарушают покупатели когорт сентября и декабря 2017 года, в которые входят самые ценные клиенты. Средняя выручка с одного покупателя - 6,9 рублей. Только у когорты покупателей марта 2018 года средняя выручка с одного покупателя выше у пользователей с мобильными устройствами. Средняя выручка с одного покупателя по категориям устройств значительно выше у покупателей со стационарными устройствами. У разных когорт разные "лидеры" среди рекламных источников по уровню средней выручки с одного покупателя - либо первый, либо второй рекламные источники. Средняя выручка с одного покупателя самая высокая от покупателей, пришедших из второго (13,38 рублей) и первого (10,72 рублей) рекламных источников, самая низкая - от покупателей, пришедших из десятого (3,35 рублей) источника. Покупатели, пришедшие из второго рекламного источника, более половины выручки приносят после нулевого месяца "жизни" когорт.
# посчитаем общую сумму затрат
total_costs = costs['costs'].agg('sum')
d = {'total_costs': total_costs}
costs_metrics_all = pd.DataFrame(data = d,
index = ['all'])
costs_metrics_all
Всего на рекламу потратили 329 131,62 рубля.
# посмотрим на общие расходы в разрезе рекламных источников
costs_metrics_source = costs.pivot_table(index = 'source_id',
values = 'costs',
aggfunc = 'sum')\
.reset_index()\
.rename(columns = {'costs':'total_costs'})
fig, ax = plt.subplots()
plt.title('Общие расходы по рекламным источникам')
ax = sns.barplot(x = 'source_id',
y = 'total_costs',
data = costs_metrics_source)
plt.xlabel('Рекламный источник')
plt.ylabel('Расходы, рублей')
ax.grid = True
plt.show()
# отсортируем затраты в разрезе рекламных источников
costs_metrics_source.sort_values(by = 'total_costs',
ascending = False)
Больше всего было потрачено на третий рекламный источник (141 321,63 рубля - более чем в 2 раза, чем на какой-либо другой), меньше всего - на девятый (5,517,49 рубля) и десятый (5 822,49 рубля) рекламные источники. На седьмой рекламный источник, из которого пришел один покупатель, затраты не осуществлялись.
# добавим в таблицу строку с нулевым значением затрат на рекламу по седьмому источнику
costs_metrics_source.loc[7] = [7, 0]
costs_metrics_source = costs_metrics_source.sort_values(by = 'source_id')
costs_metrics_source['source_id'] = costs_metrics_source['source_id'].astype('int')
costs_metrics_source
# посмотрим на динамику ежедневных расходов на рекламу
costs_date = costs.groupby('date')\
.agg({'costs': 'sum'})\
.reset_index()
fig, ax = plt.subplots()
plt.title('Динамика ежедневных расходов на рекламу')
ax = sns.lineplot(x = 'date',
y = 'costs',
data = costs_date)
plt.xlabel('Месяц')
plt.ylabel('Расходы, руб.')
plt.show()
На графике имеется множество "всплесков", которые, вероятнее всего, говорят о проведении рекламных акций в эти дни. Динамика ежедневных расходов на рекламу очень похожа на динамику ежедневных заказов, что, вероятно, свидетельствует о наличии зависимости между этими показателями.
# посчитаем коэффициент корреляции между ежедневными затратами на рекламу и ежедневным количеством заказов
orders_per_day['order_date'] = pd.to_datetime(orders_per_day['order_date'])
costs_orders_date = costs_date.merge(orders_per_day,
left_on = 'date',
right_on = 'order_date',
how = 'outer')
costs_orders_corr = costs_orders_date['costs'].corr(costs_orders_date['n_orders']).round(2)
costs_orders_corr
Полученное значение коэффициента корреляции 0,79 свидетельствует о достаточно высокой зависимости количества ежедневных заказов от ежедневных расходов на рекламу.
# добавим в таблицу столбцы с месяцем и днем недели затрат на рекламу
costs['costs_month'] = costs['date'].astype('datetime64[M]')
costs['costs_day_of_week'] = costs['date'].dt.weekday
costs.head()
# посмотрим на расходы на рекламу по дням недели
costs_month = costs.groupby('costs_day_of_week')\
.agg({'costs': 'sum'})\
.reset_index()
plt.title('Расходы на рекламу по дням недели')
ax = sns.barplot(x = 'costs_day_of_week',
y = 'costs',
data = costs_month)
plt.xlabel('День недели')
plt.ylabel('Расходы, руб.')
ax.set_xticklabels(labels = day_of_week)
plt.show()
Самые высокие затраты на рекламу в четверг и пятницу, самые низкие - в выходные дни.
# посмотрим на динамику ежемесячных расходов на рекламу
costs_month = costs.groupby('costs_month')\
.agg({'costs': 'sum'})\
.reset_index()
fig, ax = plt.subplots()
plt.title('Динамика ежемесячных расходов на рекламу')
ax = sns.lineplot(x = 'costs_month',
y = 'costs',
data = costs_month)
plt.xlabel('Месяц')
plt.ylabel('Расходы, руб.')
plt.show()
Общие расходы на рекламу начали расти с сентября 2017 года, достигли своего максимума в декабре 2017 года, после чего начали снижаться.
# посмотрим на динамику ежедневных расходов по рекламным источникам
costs_source_date = costs.groupby(['source_id',
'date'])\
.agg({'costs': 'sum'})\
.reset_index()
fig, ax = plt.subplots(figsize = (18, 12))
ax.set(title = 'Динамика ежедневных расходов на рекламу по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Расходы, руб.')
for source in costs_source_date['source_id'].unique():
ax.plot(costs_source_date.query('source_id == @source')['date'],
costs_source_date.query('source_id == @source')['costs'],
label = source)
ax.legend()
plt.show()
По всем источникам ежедневные затраты на рекламу крайне неравномерны. Декабрьский "всплеск" затрат на рекламу, вероятнее всего связанный с новогодними праздниками, достигнут исключительно благодаря третьему источнику.
# посмотрим на динамику ежемесячных расходов по рекламным источникам
costs_source_month = costs.groupby(['source_id',
'costs_month'])\
.agg({'costs': 'sum'})\
.reset_index()
fig, ax = plt.subplots(figsize = (18, 12))
ax.set(title = 'Динамика ежемесячных расходов на рекламу по рекламным источникам',
xlabel = 'Месяц',
ylabel = 'Расходы, руб.')
for source in costs_source_month['source_id'].unique():
ax.plot(costs_source_month.query('source_id == @source')['costs_month'],
costs_source_month.query('source_id == @source')['costs'],
label = source)
ax.legend()
plt.show()
Ежемесячные расходы на рекламу по всем рекламным источникам, за исключением третьего, в анализируемом периоде производились достаточно равномерно. Динамика затрат на самый "дорогой" рекламный источник - третий - соответствует динамике общих затрат на рекламу по всем источникам.
# добавим в таблицу с когортами покупателей расходы на рекламу и посчитаем CAC
report_new = report.merge(costs_month,
left_on = 'first_order_month',
right_on = 'costs_month')
report_new['cac'] = report_new['costs'] / report_new['n_buyers']
report_new.head()
# проверим общую сумму выручки
report_new['revenue'].sum()
# посмотрим на CAC по когортам
cac = report_new.groupby('first_order_month')['cac']\
.mean()\
.reset_index()
fig, ax = plt.subplots()
plt.title('CAC по когортам')
ax = sns.barplot(x = 'first_order_month',
y = 'cac',
data = cac)
ax.set_xticklabels(labels = cac['first_order_month'].dt.strftime('%Y-%m-%d'),
fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('CAC, рублей')
plt.show()
# отсортируем таблицу по показателю CAC
cac.sort_values(by = 'cac',
ascending=False)\
.reset_index(drop = True)
Самыми дорогими по стоимости привлечения оказались покупатели когорты августа 2017 года (CAC составил 10,8 рублей), января (CAC - 9,9 рублей) и апреля 2018 года (CAC - 9,8 рублей). Дешевле всего по стоимости привлечения оказались пользователи мая 2018 года (CAC - 7,4 рубля) и октября 2017 года (CAC - 8,4 рубля).
# посчитаем средний CAC по всем покупателям
cac_mean = costs['costs'].sum() / revenue_metrics_all['n_buyers']
d = {'avg_cac': cac_mean}
cac_metrics_all = pd.DataFrame(data = d,
index = ['all'])
cac_metrics_all
Средний показатель CAC по всем покупателям составил 9,01 рубль.
# добавим в таблицу с когортами покупателей расходы на рекламу и посчитаем CAC
report_source_new = report_source.merge(costs_source_month,
left_on = ['source_id',
'first_order_month'],
right_on = ['source_id',
'costs_month'],
how = 'outer')
report_source_new['cac'] = report_source_new['costs'] / report_source_new['n_buyers']
report_source_new.head()
# проверим общую сумму выручки
report_source_new['revenue'].sum()
# посмотрим на CAC по когортам по рекламным источникам
cac_source = report_source_new.groupby(['source_id',
'first_order_month'])['cac']\
.mean()\
.reset_index()
fig, ax = plt.subplots()
plt.title('CAC по когортам по рекламным источникам')
ax = sns.barplot(x = 'first_order_month',
y = 'cac',
data = cac_source,
hue = 'source_id')
ax.set_xticklabels(labels = cac_source['first_order_month'].dt.strftime('%Y-%m-%d'),
fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('CAC, рублей')
plt.show()
Во всех когортах наибольшая стоимость привлечения клиентов у второго и третьего рекламных источников, наименьшая у большинства когорт - у девятого и десятого источника.
# создадим тепловую карту с показателем CAC по рекламным источникам
cac_source_pivot = cac_source.pivot_table(index = 'source_id',
columns = 'first_order_month',
values = 'cac')
plt.figure(figsize = (15, 9))
plt.title('CAC по когортам по рекламным источникам')
ax = sns.heatmap(cac_source_pivot,
annot = True,
fmt = '.2f',
cmap = 'coolwarm',
linecolor = 'gray')
plt.xlabel('Когорта')
plt.ylabel('Рекламный источник')
ax.set_xticklabels(labels = cac_source_pivot.columns.date,
fontsize = 14,
rotation = 45)
ax.set_yticklabels(labels = cac_source_pivot.index,
rotation = 0)
plt.show()
Самая высокая стоимость привлечения клиентов CAC у когорты августа 2017 года третьим источником - 18,23 рубля, самая низкая - у когорты марта 2018 года десятым источником - 2,83 рубля.
# посчитаем средний CAC по всем покупателям по рекламным источникам
cac_mean_source = costs_metrics_source.groupby('source_id')['total_costs'].sum()\
/ revenue_metrics_source.groupby('source_id')['n_buyers'].sum()
d = {'avg_cac': cac_mean_source}
cac_metrics_source = pd.DataFrame(data = d)
cac_metrics_source = cac_metrics_source.reset_index()
cac_metrics_source
# посмотрим на средний CAC по рекламным источникам
fig, ax = plt.subplots()
plt.title('Средний CAC по рекламным источникам')
ax = sns.barplot(x = 'source_id',
y = 'avg_cac',
data = cac_metrics_source)
plt.xlabel('Рекламный источник')
plt.ylabel('CAC, рублей')
plt.show()
Самая высокая средняя стоимость привлечения покупателей CAC у третьего рекламного источника - 13,49 рублей, чуть ниже у второго - 12,21 рубль. Самый низкий средний показатель CAC у десятого рекламного источника - 4,38 рубля.
# добавим в таблицу с когортами покупателей столбец с ROMI
report_new['romi'] = report_new['ltv'] / report_new['cac']
report_new.head()
# построим сводную таблицу с показателем ROMI по когортам и lifetime
romi = report_new.pivot_table(index = 'first_order_month',
columns = 'cohort_lifetime',
values = 'romi',
aggfunc = 'mean')
romi_cumsum = romi.cumsum(axis = 1)
romi_cumsum.fillna('')
# создадим тепловую карту с показателем ROMI по рекламным источникам
plt.figure(figsize = (15, 9))
plt.title('ROMI по рекламным источникам')
ax = sns.heatmap(romi_cumsum,
annot = True,
fmt = '.2f',
cmap = 'coolwarm',
linecolor = 'gray',
yticklabels = ltv.index.date)
plt.xlabel('Lifetime')
plt.ylabel('Когорта')
plt.show()
Быстрее всего окупилась когорта сентября 2017 года, в которую входит один из двух наиболее ценных клиентов, - на 3 месяц. Самая "старая" когорта - июня 2017 года - окупилась на шестой месяц. Остальные когорты на момент окончания анализируемого периода не окупились.
# посмотрим на ROMI по когортам
romi_cohorts = report_new.groupby('first_order_month')['romi']\
.sum()\
.reset_index()
fig, ax = plt.subplots()
plt.title('ROMI по когортам')
ax = sns.barplot(x = 'first_order_month',
y = 'romi',
data = romi_cohorts)
ax.set_xticklabels(labels = romi_cohorts['first_order_month'].dt.strftime('%Y-%m-%d'), fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('ROMI')
plt.show()
# отсортируем таблицу по показателю ROMI
romi_cohorts.sort_values(by = 'romi',
ascending = False)\
.reset_index(drop = True)
Средний показатель возврата маркетинговых инвестиций ROMI выше единицы только в двух когортах - сентября (ROMI составил 1,42) и июня 2017 года (ROMI - 1,33). Самый низкий показатель ROMI у покупателей, совершивших первый заказ в январе (ROMI - 0,5), феврале (ROMI - 0,51) и апреле 2018 года (ROMI - 0,53).
# посчитаем, когда в среднем начинают окупаться когорты
romi.cumsum(axis=1).mean(axis=0)
В среднем, когорты окупаются к концу девятого - десятого месяца.
# посчитаем средний ROMI по всем покупателям
romi_mean = ltv_metrics_all['avg_ltv'] / cac_metrics_all['avg_cac']
d = {'avg_romi': romi_mean}
romi_metrics_all = pd.DataFrame(data = d,
index = ['all'])
romi_metrics_all
Средний показатель ROMI по всем покупателям составил 0,77, т.е. по всей совокупности наши затраты не окупились.
# добавим в таблицу с когортами покупателей столбец с ROMI
report_source_new['romi'] = report_source_new['ltv'] / report_source_new['cac']
report_source_new.head()
# посмотрим на ROMI по когортам по рекламным источникам
romi_cohorts_source = report_source_new.groupby(['source_id',
'first_order_month'])['romi']\
.sum()\
.reset_index()
fig, ax = plt.subplots()
plt.title('ROMI по когортам по рекламным источникам')
ax = sns.barplot(x = 'first_order_month',
y = 'romi',
data = romi_cohorts_source,
hue = 'source_id')
ax.set_xticklabels(labels = romi_cohorts_source['first_order_month'].dt.strftime('%Y-%m-%d'),
fontsize = 14)
plt.xlabel('Когорта')
plt.ylabel('ROMI')
plt.show()
Для разных когорт среди рекламных источников разные "лидеры" по показателю возврата маркетинговых инвестиций ROMI. Самый "дорогой" рекламный источник - третий - до конца анализируемого периода не окупился ни у одной из когорт.
# посчитаем количество когорт с ROMI больше 1
romi_cohorts_source.query('romi >= 1')\
.groupby('source_id')['romi']\
.count()\
.sort_values(ascending = False)
У семи из 12 когорт средний показатель возврата маркетинговых инвестиций ROMI выше единицы у покупателей из первого рекламного источника, у 6 - из второго, у 5 - из девятого.
# создадим тепловую карту с показателем ROMI по рекламным источникам
romi_source_pivot = romi_cohorts_source.pivot_table(index = 'source_id',
columns = 'first_order_month',
values = 'romi')
plt.figure(figsize = (15, 9))
plt.title('ROMI по когортам по рекламным источникам')
ax = sns.heatmap(romi_source_pivot,
annot = True,
fmt = '.2f',
cmap = 'coolwarm',
linecolor = 'gray')
plt.xlabel('Когорта')
plt.ylabel('Рекламный источник')
ax.set_xticklabels(labels = romi_source_pivot.columns.date,
fontsize = 14,
rotation = 45)
ax.set_yticklabels(labels = romi_source_pivot.index,
rotation = 0)
plt.show()
Самый высокий средний показатель возврата маркетинговых инвестиций ROMI у когорты июня 2017 года первым источником (ROMI - 5,68) и сентября 2017 года пятым (ROMI - 4), самый низкий - у когорты января 2018 года третьим источником (0,31).
# посчитаем средний ROMI по всем покупателям по рекламным источникам
romi_mean_source = ltv_metrics_source.groupby('source_id')['avg_ltv'].first()\
/ cac_metrics_source.groupby('source_id')['avg_cac'].first()
romi_mean_source[7] = 0
d = {'avg_romi': romi_mean_source}
romi_metrics_source = pd.DataFrame(data = d)
romi_metrics_source = romi_metrics_source.reset_index()
romi_metrics_source
# посмотрим на средний ROMI по рекламным источникам
fig, ax = plt.subplots()
plt.title('Средний ROMI по рекламным источникам')
ax = sns.barplot(x = 'source_id',
y = 'avg_romi',
data = romi_metrics_source)
plt.xlabel('Рекламный источник')
plt.ylabel('ROMI')
plt.show()
К концу анализируемого периода окупились 4 рекламных источника: первый (ROMI - 1,49), второй (ROMI - 1,1), девятый (ROMI - 1,04) и пятый (ROMI - 1,02). У самого затратного рекламного источника - третьего - показатель возврата маркетинговых инвестиций ROMI самый низкий - всего 0,39.
# сведем в одну таблицу все рассчитанные маркетинговые метрики
marketing_metrics_all = pd.concat([costs_metrics_all,
cac_metrics_all,
romi_metrics_all],
axis = 1)
marketing_metrics_all_tr = marketing_metrics_all.transpose()
marketing_metrics_all_tr
# сведем в одну таблицу все рассчитанные маркетинговые метрики по рекламным источникам
marketing_metrics_source = costs_metrics_source.merge(cac_metrics_source, on = 'source_id')\
.merge(romi_metrics_source, on = 'source_id')
marketing_metrics_source.set_index('source_id', inplace = True)
marketing_metrics_source_tr = marketing_metrics_source.transpose()
marketing_metrics_source_tr
1. Всего на рекламу потратили 329 131,62 рубля. Больше всего было потрачено на третий рекламный источник (141 321,63 рубля - более чем в 2 раза, чем на какой-либо другой), меньше всего - на девятый (5,517,49 рубля) и десятый (5 822,49 рубля) рекламные источники. На седьмой рекламный источник, из которого пришел один покупатель, затраты не осуществлялись.
2. Динамика ежедневных расходов на рекламу имеет множество "всплесков", которые, вероятнее всего, говорят о проведении рекламных акций в эти дни. Динамика ежедневных расходов на рекламу очень похожа на динамику ежедневных заказов, что, вероятно, свидетельствует о наличии зависимости между этими показателями. Полученное значение коэффициента корреляции 0,79 подтвердило предположение об этой зависимости. По дням недели - самые высокие затраты на рекламу в четверг и пятницу, самые низкие - в выходные дни. Общие расходы на рекламу начали расти с сентября 2017 года, достигли своего максимума в декабре 2017 года, после чего начали снижаться. По всем источникам ежедневные затраты на рекламу крайне неравномерны. Декабрьский "всплеск" затрат на рекламу, вероятнее всего связанный с новогодними праздниками, достигнут исключительно благодаря третьему источнику.
Ежемесячные расходы на рекламу по всем рекламным источникам, за исключением третьего, в анализируемом периоде производились достаточно равномерно. Динамика затрат на самый "дорогой" рекламный источник - третий - соответствует динамике общих затрат на рекламу по всем источникам.
1. Самыми дорогими по стоимости привлечения оказались покупатели когорты августа 2017 года (CAC составил 10,8 рублей), января (CAC - 9,9 рублей) и апреля 2018 года (CAC - 9,8 рублей). Дешевле всего по стоимости привлечения оказались пользователи мая 2018 года (CAC - 7,4 рубля) и октября 2017 года (CAC - 8,4 рубля). Средний показатель CAC по всем покупателям составил 9,01 рубль. Во всех когортах наибольшая стоимость привлечения клиентов у второго и третьего рекламных источников, наименьшая у большинства когорт - у девятого и десятого источника. Самая высокая стоимость привлечения клиентов у когорты августа 2017 года третьим источником - 18,23 рубля, самая низкая - у когорты марта 2018 года десятым источником - 2,83 рубля. Самая высокая средняя стоимость привлечения покупателей у третьего рекламного источника - 13,49 рублей, чуть ниже у второго - 12,21 рубль. Самый низкий средний показатель CAC у десятого рекламного источника - 4,38 рубля.
2. Быстрее всего окупилась когорта сентября 2017 года, в которую входит один из двух наиболее ценных клиентов, - на 3 месяц. Самая "старая" когорта - июня 2017 года - окупилась на шестой месяц. Остальные когорты на момент окончания анализируемого периода не окупились.
1. Средний показатель возврата маркетинговых инвестиций ROMI выше единицы только в двух когортах - сентября (ROMI составил 1,42) и июня 2017 года (ROMI - 1,33). Самый низкий показатель ROMI у покупателей, совершивших первый заказ в январе (ROMI - 0,5), феврале (ROMI - 0,51) и апреле 2018 года (ROMI - 0,53). В среднем, когорты окупаются к концу девятого - десятого месяца.
Средний показатель ROMI по всем покупателям составил 0,77, т.е. по всей совокупности затраты не окупились. Для разных когорт среди рекламных источников разные "лидеры" по показателю возврата маркетинговых инвестиций. Самый "дорогой" рекламный источник - третий - до конца анализируемого периода не окупился ни у одной из когорт. У семи из 12 когорт средний показатель возврата маркетинговых инвестиций выше единицы у покупателей из первого рекламного источника, у 6 - из второго, у 5 - из девятого. Самый высокий средний показатель возврата маркетинговых инвестиций у когорты июня 2017 года первым источником (ROMI - 5,68) и сентября 2017 года пятым (ROMI - 4), самый низкий - у когорты января 2018 года третьим источником (0,31).
2. К концу анализируемого периода окупились 4 рекламных источника: первый (ROMI - 1,49), второй (ROMI - 1,1), девятый (ROMI - 1,04) и пятый (ROMI - 1,02). У самого затратного рекламного источника - третьего - показатель возврата маркетинговых инвестиций ROMI самый низкий - всего 0,39.
Уникальных пользователей со стационарными устройствами более чем в 2,3 раза больше, чем с мобильными, в связи с чем у них выше и все показатели пользовательской активности. Показатели вовлечённости пользователей у посетителей сайта со стационарных устройств тоже выше, но незначительно. В свою очередь среднее количество сессий в день у пользователей со стационарными устройствами более чем в 2,7 раза больше, чем с мобильными, а среднее количство сессий в день на одного пользователя у них выше совсем незначительно - всего на 4%. Колебания количества сессий в день значительно выше при использовании стационарных устройств, кроме того, ни в один из дней не было превышения случаев использования мобильных устройств для посещения сайта по сравнению со стационарными. В динамике ежедневного количества сессий, приходящихся на одного пользователя, по категориям устройств наблюдаются более значительные колебания этого показателя у пользователей мобильных устройств, кроме того есть дни, когда количество сессий, приходящихся на одного пользователя, выше именно у посетителей сайта из мобильных устройств. Значения средней продолжительности сессии в разрезе категорий устройств равны. Средний коэффициент удержания Retention Rate по первому месяцу "жизни" когорты у пользователей со стационарными устройствами немного выше, чем у пользователей с мобильными. И покупатели со стационарными устройствами, и с мобильными в основном первые покупки совершают в первый день посещения сайта. В то же время, пользователям мобильных устройств требуется больше времени, чтобы совершить покупку после первого посещения (для 75% пользователей устройств это период до 6 дней). Более 15% посещений сайта со стационарных устройств связано с осуществлением заказов, у пользователей мобильных устройств "холостых" посещений значительно больше (заказы осуществлялись менее, чем в 10% посещений). У покупателей со стационарными устройствами показатели среднего количества заказов в день и месяц более чем в 4 раза выше, чем у покупателей с мобильными. Количество заказов в день со стационарных устройств подвержено большим колебаниям, чем с мобильных. Декабрьский "всплеск" количества заказов, вероятнее всего связанный с новогодними праздниками, был достигнут в основном за счет покупателей, использующих стационарные устройства. Количество заказов в месяц у пользователей стационарных устройств также подвержено большим колебаниям, тогда как количество заказов у пользователей мобильных устройств из месяца в месяц практически не меняется. Общая выручка от покупателей со стационарными устройствами в 5 раз больше выручки от покупателей с мобильными устройствами. Средний и медианный чек, а также количество покупателей и среднее количество заказов на одного покупателя также выше у пользователей, приходящих на сайт со стационарных устройств. Средний чек пользователей, заходящих на сайт со стационарных устройств, выше, чем у использующих мобильные устройства, в основном за счет нескольких дней с весьма высокими значениями среднего чека. Только в ноябре 2017 года средний чек пользователей с мобильными устройствами был выше, чем у пользователей со стационарными устройствами. Средний чек декабря 2017 года у покупателей с разными устройствами находится на разных "полюсах". Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" у пользователей с мобильными устройствами в течение "жизни" когорт снижается медленнее, чем у пользователей со стационарными устройствами. Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты выше у пользователей со стационарными устройствами. Только у когорты покупателей марта 2018 года средняя выручка с одного покупателя выше у пользователей с мобильными устройствами. Средняя выручка с одного покупателя по категориям устройств значительно выше у покупателей со стационарными устройствами.
# проранжируем метрики по рекламным источникам
metrics_source = product_metrics_source.merge(trading_metrics_source,
left_index = True,
right_index = True)\
.merge(marketing_metrics_source,
left_index = True,
right_index = True)
metrics_source = metrics_source.reset_index()
metrics_source = metrics_source.drop(index = 5)
metrics_source.set_index('source_id',
inplace = True)
metrics_source = metrics_source.transpose()
metrics_source_rank = metrics_source.rank(ascending = False,
axis = 1)\
.astype('int')
metrics_source_rank
Наибольшее общее количество уникальных пользователей привлечено на сайт при помощи четвертого и третьего рекламных источников, соответственно у этих источников выше и все показатели пользовательской активности. Через шестой и седьмой рекламные источники пользователи практически не привлекались. Показатели вовлечённости аудитории выше у первого и второго рекламных источников. Среднее количество сессий в день наибольшее у пользователей из третьего и четвертого рекламных источников, однако показатели количества сессий в день на одного пользователя иные. Здесь наилучшие значения этого показателя у пользователей из первого источника. У третьего и четвертого рекламных источников, при помощи которых пользователи посещали сайт чаще, количество сессий в день на одного пользователя очень мала. Динамика количества сессий в день по рекламным источникам очень похожа, декабрьский "пик" при этом достигнут, в основном, благодаря пользователям, пришедшим из третьего и четвертого рекламных источников. Динамика количества сессий в день на одного пользователя по рекламным источникам подвержена более значительным колебаниям, при этом у первого рекламного источника имеется самое большое количество "всплесков" этого показателя. Значения средней продолжительности сессии в разрезе рекламных источников равны, за исключением шестого и седьмого рекламных источников, при помощи которых привлечено совсем небольшое количество пользователей. Из двух рекламных источников с наибольшим привлечением пользователей - третьего и четвертого - коэффициент удержания Retention Rate по первому месяцу "жизни" когорты у третьего источника очень низок. Более 15% пользователей, привлеченных с использованием девятого, второго и первого рекламных источников, возвращаются на сайт в первый месяц "жизни" когорты. Покупатели, пришедшие из всех рекламных источников, в основном первые покупки совершают в первый день посещения сайта. Среди рекламных источников самыми "медленными" являются пользователи, привлеченные на сайт при помощи девятого источника (для 75% пользователей, пришедших из этого источника, требуется до 70 дней, чтобы совершить покупку после первого посещения). У пользователей, посетивших сайт при помощи первого, третьего и десятого рекламных источников, более 15% посещений сайта связано с осуществлением заказов, у седьмого источника лишь одно посещение из 36 привело к осуществлению заказа. Самые высокие значения среднего количество заказов в день и месяц у покупателей, пришедших из третьего и четвертого рекламных источников. У самых популярных рекламных источников (третьего и четвертого) рост количества заказов начался с сентября 2017 года, до этого они практически не выделялись на фоне других источников. Декабрьский "всплеск" количества заказов, вероятнее всего связанный с новогодними праздниками, был обеспечен в основном именно этими источниками. Самая большая выручка от покупателей, привлеченных на сайт при помощи четвертого, третьего и пятого рекламных источников, однако самый высокий средний чек от пользователей, пришедших из второго рекламного источника. В то же время, у этого рекламного источника медианный чек не самый высокий из-за присутствия в группе одного из самых "ценных" покупателей. Наибольшее количество покупателей пришли с помощью третьего и четвертого рекламных источников, однако самые высокие показатели среднего количества заказов на одного покупателя у второго и первого рекламных источников. У пятого рекламного источника в один из дней декабря 2017 года есть очень высокое значение среднего чека, вероятнее всего связанное с разовой крупной покупкой. Наибольшее количество "пиковых" дней с высокими значениями среднего чека у второго рекламного источника. Средний чек в месяц практически по всем рекламным источникам из месяца в месяц меняется незначительно, за исключением пятого источника с большим значением среднего чека в декабре 2017 года, и второго источника с "всплеском" в феврале - марте 2018 года. Средний показатель ценности клиента LTV без учета нулевого месяца "жизни" в течение "жизни" когорт растет только у покупателей, пришедших на сайт с помощью первого рекламного источника. Средний показатель ценности клиента LTV по нулевому месяцу "жизни" когорты самый высокий у покупателей, посетивших сайт при помощи второго и первого рекламных источников. У разных когорт разные "лидеры" среди рекламных источников по уровню средней выручки с одного покупателя - либо первый, либо второй рекламные источники. Средняя выручка с одного покупателя самая высокая от покупателей, пришедших из второго и первого рекламных источников, самая низкая - от покупателей, пришедших из десятого источника. Покупатели, пришедшие из второго рекламного источника, более половины выручки приносят после нулевого месяца "жизни" когорт. Больше всего было потрачено на третий рекламный источник (более чем в 2 раза, чем на какой-либо другой), меньше всего - на девятый и десятый рекламные источники. На седьмой рекламный источник, из которого пришел один покупатель, затраты не осуществлялись. Ежемесячные расходы на рекламу по всем рекламным источникам, за исключением третьего, в анализируемом периоде производились достаточно равномерно. Во всех когортах наибольшая стоимость привлечения клиентов у второго и третьего рекламных источников, наименьшая у большинства когорт - у девятого и десятого источника. Самая высокая стоимость привлечения клиентов у когорты августа 2017 года третьим источником, самая низкая - у когорты марта 2018 года десятым источником. Самая высокая средняя стоимость привлечения покупателей у третьего рекламного источника, чуть ниже у второго. Самый низкий средний показатель CAC у десятого рекламного источника. Для разных когорт среди рекламных источников разные "лидеры" по показателю возврата маркетинговых инвестиций. Самый "дорогой" рекламный источник - третий - до конца анализируемого периода не окупился ни у одной из когорт. У семи из 12 когорт средний показатель возврата маркетинговых инвестиций выше единицы у покупателей из первого рекламного источника, у 6 - из второго, у 5 - из девятого. Самый высокий средний показатель возврата маркетинговых инвестиций у когорты июня 2017 года первым источником и сентября 2017 года пятым, самый низкий - у когорты января 2018 года третьим источником. К концу анализируемого периода окупились 4 рекламных источника: первый (ROMI - 1,49), второй (ROMI - 1,1), девятый (ROMI - 1,04) и пятый (ROMI - 1,02). У самого затратного рекламного источника - третьего - показатель возврата маркетинговых инвестиций ROMI самый низкий - всего 0,39.